Hvorfor virker det ikke med GROUP BY
SELECT *
kan ikke bruges med GROUP BY
; det er ugyldig SQL. GROUP BY
vælger ikke tabelrækker. Den opretter grupper af rækker ved hjælp af de angivne udtryk, og fra hver gruppe genererer den en ny post og beregner hver kolonne i denne nye post ved hjælp af de værdier, der er involveret i udtrykket.
De kolonner, der vises i SELECT
klausul skal opfylde en af følgende regler:
- optræder også i
GROUP BY
klausul; - bruges med
GROUP BY
aggregerede funktioner ; - er funktionelt afhængige af de kolonner, der vises i
GROUP BY
klausul.
Mens *
er en genvej til alle kolonnenavnene på tabellen(erne), der bruges af forespørgslen, for din forespørgsel kun user
kolonnen opfylder et af kravene ovenfor.
Før version 5.7.5
MySQL implementerede ikke den tredje regel ovenfor. Det plejede at acceptere forespørgsler, der indeholdt i SELECT
klausulkolonner, der ikke følger nogen af GROUP BY
krav. Den værdi, der blev returneret af forespørgslen for sådanne kolonner, var ubestemt
.
Siden version 5.7.5 afviser MySQL GROUP BY
forespørgsler, der opfylder kravene.
Løsningen
Uanset hvad, så involverer løsningen af dit problem ikke GROUP BY
. Det kan nemt opnås ved at bruge en LEFT JOIN
med de korrekte betingelser:
SELECT lc.*
FROM comments lc # 'lc' from 'last comment'
LEFT JOIN comments nc # 'nc' from 'newer comment'
ON lc.user = nc.user # both comments belong to the same user
AND lc.id < nc.id # 'nc' is newer than 'lc'
WHERE nc.id IS NULL # there is no 'newer comment'
ORDER BY lc.id DESC
LIMIT 10
Sådan virker det
Det forbinder tabellen comments
, kaldet lc
("lc" fra den "sidste kommentar" fra en bruger) mod sig selv, kaldet nc
("nc" fra "nyere kommentar"). Join-klausulen matcher hver indgang i lc
med alle indtastninger af nc
der tilhører den samme bruger (lc.user = nc.user
) og er nyere (lc.id < nc.id
; Jeg antog, at id'erne er tildelt sekventielt, og nyere kommentarer har større værdier for id
).
Brugen af LEFT JOIN
sikrer, at hver række af lc
vises i resultatet af joinforbindelsen, selv når der ikke findes nogen matchende række i nc
(fordi der ikke er nogen nyere kommentar fra den samme bruger). I dette tilfælde NULL
bruges i stedet for felterne i nc
. WHERE
klausul beholder i det endelige resultatsæt kun de rækker, der har NULL
i nc.id
; dette betyder i lc
del, de indeholder den seneste kommentar fra hver bruger.
SELECT
klausulen indeholder alle felterne i lc
(dem af nc
er alle NULL
, alligevel). ORDER BY
klausul kan bruges til at sortere resultatsættet. ORDER BY lc.id DESC
sætter de seneste kommentarer først og LIMIT
klausul holder resultatet sat til en anstændig størrelse.