Den første ting at gøre det klart er, at SQL ikke er MySQL.
I standard SQL er det ikke tilladt at gruppere efter en delmængde af de ikke-aggregerede felter. Årsagen er meget enkel. Antag, at jeg kører denne forespørgsel:
SELECT color, owner_name, COUNT(*) FROM cars
GROUP BY color
Den forespørgsel ville ikke give nogen mening. Selv at prøve at forklare det ville være umuligt. Det er helt sikkert at vælge farver og tælle antallet af biler pr. farve. Det tilføjer dog også owner_name
felt, og der kan være mange ejere for en given farve, da det er tilfældet med White
farve. Så hvis der kan være mange owner_name
værdier for en enkelt color
som tilfældigvis er det eneste felt i GROUP BY
klausul... så hvilken owner_name
vil blive returneret?
Hvis det er nødvendigt at returnere et owner_name
så skal der tilføjes en slags kriterier for kun at vælge et af dem, f.eks. det første alfabetisk, hvilket i dette tilfælde ville være John
. Dette kriterium ville resultere i tilføjelse af en samlet funktion MIN(owner_name)
og så vil forespørgslen give mening igen, da den vil blive grupperet efter i det mindste alle de ikke-aggregerede felter i select-sætningen.
Som du kan se, er der en klar og praktisk grund til, at standard SQL er ufleksibel i grupperingen. Hvis det ikke var det, kunne du stå over for akavede situationer, hvor værdien for en kolonne vil være uforudsigelig, og det er ikke et pænt ord, især hvis forespørgslen, der køres, viser dig dine bankkontotransaktioner.
Når det er sagt, hvorfor ville MySQL så tillade forespørgsler, der måske ikke giver mening? Og endnu værre, fejlen i forespørgslen ovenfor kunne blot syntaktisk opdages! Det korte svar er:ydeevne. Det lange svar er, at der er visse situationer, hvor det, baseret på datarelationer, at få en uforudsigelig værdi fra gruppen vil resultere i en forudsigelig værdi.
Hvis du ikke har fundet ud af det endnu, vil den eneste måde, hvorpå du kan forudsige den værdi, du får ved at tage et uforudsigeligt element fra en gruppe, være, hvis alle elementerne i gruppen er ens. Et tydeligt eksempel på denne situation er i eksempelforespørgslen i dit samme spørgsmål. Se hvordan owner_id
og owner_name
vedrører i tabellen. Det er klart, at givet enhver owner_id
, for eksempel. 2
, kan du kun have ét særskilt owner_name
. Selvom du har mange rækker, vil du få Mike
ved at vælge nogen som resultat. I formel database-jargon kan dette forklares som owner_id
bestemmer funktionelt owner_name
.
Lad os se nærmere på den fuldt fungerende MySQL-forespørgsel:
SELECT owner_id, owner_name, COUNT(*) total FROM cars
GROUP BY owner_id
Givet enhver owner_id
dette ville returnere den samme owner_name
, så føje den til GROUP BY
klausul vil ikke resultere i, at flere rækker returneres. Selv tilføjelse af en aggregeret funktion MAX(owner_name)
vil ikke resultere i, at færre rækker returneres. De resulterende data vil være nøjagtig de samme. I begge tilfælde ville forespørgslen straks blive omdannet til en juridisk standard SQL-forespørgsel, da i det mindste alle ikke-aggregerede felter ville blive grupperet efter. Så der er 3 tilgange til at få de samme resultater.
Men som jeg nævnte før, har denne ikke-standardiserede gruppering en ydeevnefordel. Du kan tjekke dette så undervurderede link hvori dette er forklaret mere detaljeret, men jeg vil citere den vigtigste del:
En ting, der er værd at nævne, er, at resultaterne ikke nødvendigvis er forkerte men snarere ubestemt . Med andre ord, at få de forventede resultater betyder ikke, at du har skrevet den rigtige forespørgsel. At skrive den rigtige forespørgsel vil altid give dig de forventede resultater.
Som du kan se, kan det være værd at anvende denne MySQL-udvidelse til GROUP BY
klausul. Uanset hvad, hvis dette ikke er 100 % klart endnu, så er der en tommelfingerregel, der vil sikre, at din gruppering altid vil være korrekt:Grupper altid, i det mindste, efter alle de ikke-aggregerede felter i select-sætningen . Du spilder måske et par CPU-cyklusser i visse situationer, men det er bedre end at returnere ubestemt resultater. Hvis du stadig er bange for ikke at gruppere korrekt, skal du ændre ONLY_FULL_GROUP_BY
SQL-tilstand kunne være en sidste udvej :)
Må din gruppering være korrekt og effektiv... eller i det mindste korrekt.