webForumDet fria alternativet

Behöver hjälp med att modifiera en INNER JOIN-sats

Databaser & SQL

11 svar · 669 visningar · startad av Rixn

Medlem sedan jan. 20076 inlägg
Frågan#1

För mina webbspels resultathantering (än så länge bara tre spel) har jag följande kod:

$getGamePrefs = "SELECT PlayerParameters.pName, PlayerScoresPB.pScore FROM PlayerParameters INNER JOIN PlayerScoresPB ON PlayerParameters.pID=PlayerScoresPB.pID";

vilket genererar alla spelarnamn som har minst ett resultat i något spel Det resulterar i att samma namn dyker upp flera gånger - en gång för varje spel spelaren har resultat i och det är inte riktigt vad jag är ute efter.

Det jag vill ha hjälp med i första hand är hur jag kan förändra min kod till att få fram alla namn som saknar resultat.
I andra hand vill jag gärna veta hur jag gör för att få fram olika varianter på villkor för de saknade resultaten - se nedan:

Jag vill få fram alla namn som:

  1. saknar resultat i något av spelen.
  2. saknar resultat i ett specifikt spel.
  3. saknar resultat i ett ospecificerat spel.
  4. saknar resultat i ett bestämt antal ospecificerade spel.
  5. saknar resultat i ett bestämt antal specifika spel.
Medlem sedan dec. 20025 483 inlägg
#2

De som saknar resultat öht.:

select pp.pname
  from playerParameters pp
 where pp.pid
not in ( select ps.pid
           from playerScoresPB ps )

De som saknar resultat i ett specifikt spel:

select pp.pname
  from playerParameters pp
 where pp.pid
not in ( select ps.pid
           from playerScoresPB ps
         inner
           join <game table name> g
             on s.<game id> = g.<id>
          where g.<name> = "game's name" )

För att sakna resultat i fler spel än game's name, lägger du till or "game's 2 name" efter.

De som saknar resultat i ett ospecificerat antal spel:

select pp.pname, count(distinct ps.<game id>)
  from playerParameters pp
 left
  join playerScoresPB ps
    on pp.pid = ps.pid
group
    by pp.pname
having count(distinct ps.<game id>)
     < ( select count(*)
           from <game table name> )

Den senare kan du modifiera till att bestämma ett specifikt antal spel genom att byta < mot =, och lägga till +N efter having count(...) där N är antalet spel som resultat skall saknas i. För att sakna resultat i, säg, tre spel:

select pp.pname, count(distinct ps.<game id>)
  from playerParameters pp
 left
  join playerScoresPB ps
    on pp.pid = ps.pid
group
    by pp.pname
having count(distinct ps.<game id>)+3
     = ( select count(*)
           from <game table name> )

Välkommen till wF!

Medlem sedan jan. 20076 inlägg
#3

Wow, tack - det här var ju verkligen heltäckande. Nu har jag och jobba med... fast...

Det är bara en liten sak som jag funderar över och det är förkortningarna pp och ps du har i dina exempel.
Vad betyder de?

Först trodde jag du inte ville skriva ut tabellnamnen, men sen såg jag att de fanns med de också, t ex i "from playerParameters pp". Det skulle ju då bli "from playerParameters playerParameters" vilket jag inte känner igen. Sen dök en annan tanke upp - att de skulle vara någon förkortad version av "playerParameters AS pp" men i så fall borde ovan exempel bli "from pp pp". Ridå!

Hoppas du kan hjälpa mig lite mer på traven så jag verkligen får nytta av den hjälp du gett mig hittills. Jag är väldigt sugen på att ta tag i exemplen, men fastnat. Tack på forehand!

..och tack för välkomnandet! Det är suveränt att ha den här möjligheten. Hoppas jag bara kan bjuda tillbaka med kunskap längre fram.

Medlem sedan dec. 20025 483 inlägg
#4

De är alias för tabellerna; med sådana slipper du alltså skriva ut långa tabellnamn för att kvalificera kolumnerna.

Red.:

Rixn skrev:

Sen dök en annan tanke upp - att de skulle vara någon förkortad version av "playerParameters AS pp"

Det stämmer att det är en förkortning av As .... Du kan lika gärna använda den varianten.

:bire

Medlem sedan jan. 20076 inlägg
#5

Ok fint!
Så då kan man skriva första exemplet så här istället då?

select pp.pname
  from playerParameters AS pp
  where pp.pid
  not in (select ps.pid
           from playerScoresPB AS ps)

AS-bestämningen fungerar alltså retroaktivt, dvs jag kallar ju på "pp" innan det är satt som alias till "playerParameters "?

Sen är jag ny till konstruktionen där du kallar på en ny SELECT-sats.
Hur fungerar det?
Hur ska jag tänka?

Medlem sedan dec. 20025 483 inlägg
#6

Troligtvis kallar du inte på "pp" innan det sätts som alias. SQL-frågan bearbetas först av DBMS där den joinar tabeller och utför villkorssatser; SELECT görs sist av allt.

Fenomenet med nästlade SELECT-satser kallas subqueries. Den utförs innan den omslutande frågan och returnerar mängd av information som är till nytta för den yttre. Det är svårt att beskriva hur man skall tänka. Klart är att du får överge tillvägagångssätt inom ex. PHP, för att i stället fundera i tabeller och mängder.

Mer - och utförligare - beskrivningar torde forumets SQL-gurus kunna bidra med.

Medlem sedan jan. 20076 inlägg
#7

Nu har jag läst in mig på "subqueries" och förstår vad de är till för och hur de används. Det behövs lite jobb med tester för att min användning av dem ska sitta, men det får ta sin tid. Nu vet jag i alla fall grunderna så pass att jag kan gå vidare med dina exempel.

Då tänkte jag bara fråga, för att lära mig mer, hur man kan lösa första exemplet utan "subqueries"? Jag förutsätter att det går att lösa med en JOIN-sats.

SELECT pP.pName
  FROM playerParameters AS pP
  WHERE pP.pID
  NOT IN (SELECT pS.pID
            FROM playerScoresPB AS pS)

Om jag lär mig skillnaden kan jag lättare förstå när jag ska använda respektive metod.

(Jag kör med AS ett tag till tills det sitter, sen kan jag börja med den kortare varienten.)

Medlem sedan dec. 20025 483 inlägg
#8
select pp.pname
  from playerParameters pp
left outer
  join playerScoresPB ps
    on pp.pid = ps.pid
 where ps.pid is null
Medlem sedan jan. 20076 inlägg
#9

Ok, nu har jag läst in mig mer på Subqueries och JOIN-satser så jag förstår bättre hur de fungerar och hur jag ska använda dem. Jag har börjat testa lite mer och försöker använda den koden du som ger de namn som saknar resultat i ett specifikt spel (alternativ två i din uppräkning).

Jag har "snyggat" till den så att den känns enklare för mig att använda och fyllt i de uppgifter du inte hade tillgång till (InGameParameters och variabeln för valt spel: $GameID. Så här blev det då:

$gTmp01 = "SELECT PP.pName, PP.pID 
	   FROM PlayerParameters AS PP 
	   WHERE PP.pID NOT IN (SELECT PS.pID 
			   	FROM PlayerScoresPB AS PS INNER JOIN InGameParameters AS IgP 
				ON PS.gID = IgP.gID 
				WHERE InGameParameters.gID = $GameID)";

Jag får negativt svar på mysql_query($gTmp01).
Kan du hitta några fel i koden?

Sen har jag en till liten fråga: Vilket är bäst - att skriva hela SELECT-satsen på en rad eller dela upp den som ovan? Vad är brukligt? Fördelar/nackdelar med de två sätten?

Medlem sedan juni 200032 967 inlägg
#10

Jag får negativt svar på mysql_query($gTmp01).

Vad betyder "negativt svar"? Om du kör SQL-frågan på en php-sida, se till att du får ut alla felmeddelanden du behöver för felsökning. Prova också att köra frågan direkt i MySQL / via ex. phpmyadmin.

Eventuellt kan ett problem vara att du i WHERE i din subquery har skrivit InGameParameters.gID, trots att du gett tabellen aliaset IgP. Byt till aliasnamnet istället.

Sen har jag en till liten fråga: Vilket är bäst - att skriva hela SELECT-satsen på en rad eller dela upp den som ovan? Vad är brukligt? Fördelar/nackdelar med de två sätten?

Det som är tydligast är bäst.

Medlem sedan jan. 20076 inlägg
#11

Jag bytte till IgP och då fungerade det! :-)
Tackar tackar!

Ang. det negativa svaret så avsåg jag svaret: "Det gick inte att hämta information från databasen!" jag fick från mysql_query-frågan jag använder för att hämta fram resultet:

$GamePrefs = mysql_query($getGamePrefs) or die("Det gick inte att hämta information från databasen!");
Medlem sedan juni 200032 967 inlägg
#12

Rixn skrev:

Ang. det negativa svaret så avsåg jag svaret: "Det gick inte att hämta information från databasen!" jag fick från mysql_query-frågan jag använder för att hämta fram resultet:

$GamePrefs = mysql_query($getGamePrefs) or die("Det gick inte att hämta information från databasen!");

Ok. Ta för vana att alltid ta hand om felet från MySQL.

..... or die(mysql_error());

mvh

265 ms totalt · 4 externa anrop · v20260731065814-full.86ec41c2
118 ms — deklarationer (db)
0 ms — hämta statistik (cache)
141 ms — hämta tråd, inlägg och bilagor (db)
121 ms — ändringar (db)