Waarom het niet werkt met GROUP BY
SELECT *
kan niet worden gebruikt met GROUP BY
; het is een ongeldige SQL. GROUP BY
selecteert geen tabelrijen. Het maakt groepen rijen met behulp van de opgegeven uitdrukkingen en genereert vervolgens van elke groep een nieuw record en berekent elke kolom van dit nieuwe record met behulp van de waarden die bij de uitdrukking betrokken zijn.
De kolommen die verschijnen in de SELECT
clausule moet aan een van de volgende regels voldoen:
- verschijnen ook in de
GROUP BY
clausule; - worden gebruikt met
GROUP BY
geaggregeerde functies ; - zijn functioneel afhankelijk van de kolommen die verschijnen in de
GROUP BY
clausule.
Terwijl *
is een snelkoppeling voor alle kolomnamen van de tabel(len) die door de zoekopdracht worden gebruikt, voor uw zoekopdracht alleen de user
kolom voldoen aan een van de bovenstaande vereisten.
Vóór versie 5.7.5
MySQL heeft de derde regel hierboven niet geïmplementeerd. Vroeger accepteerde het zoekopdrachten die in de SELECT
clausulekolommen die niet volgen op een van de GROUP BY
vereisten. De waarde die door de zoekopdracht voor dergelijke kolommen werd geretourneerd, was onbepaald
.
Sinds versie 5.7.5 weigert MySQL de GROUP BY
zoekopdrachten die wel aan de vereisten voldoen.
De oplossing
Hoe dan ook, de oplossing voor uw probleem is niet GROUP BY
. Het kan eenvoudig worden bereikt met een LEFT JOIN
met de juiste voorwaarden:
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
Hoe het werkt
Het voegt zich bij de tabel comments
, alias lc
("lc" van de "laatste opmerking" van een gebruiker) tegen zichzelf, alias nc
("nc" van "nieuwere opmerking"). De join-clausule komt overeen met elke invoer van lc
met alle vermeldingen van nc
die bij dezelfde gebruiker horen (lc.user = nc.user
) en zijn nieuwer (lc.id < nc.id
; Ik nam aan dat de ID's opeenvolgend worden toegewezen en dat nieuwere opmerkingen grotere waarden hebben voor id
).
Het gebruik van LEFT JOIN
zorgt ervoor dat elke rij van lc
verschijnt in het resultaat van de samenvoeging, zelfs als er geen overeenkomende rij is gevonden in nc
(omdat er geen nieuwere opmerking van dezelfde gebruiker is). In dit geval NULL
wordt gebruikt in plaats van de velden van nc
. De WHERE
clausule behoudt in de uiteindelijke resultaatset alleen de rijen die NULL
. hebben in nc.id
; dit betekent in de lc
deel bevatten ze de meest recente opmerking van elke gebruiker.
De SELECT
clausule bevat alle velden van lc
(die van nc
zijn allemaal NULL
, hoe dan ook). De ORDER BY
clausule kan worden gebruikt om de resultatenset te sorteren. ORDER BY lc.id DESC
plaatst de meest recente opmerkingen eerst en de LIMIT
clausule houdt het resultaat ingesteld op een behoorlijke omvang.