sql >> Database teknologi >  >> RDS >> Mysql

MySQL:Total GROUP BY WITH ROLLUP nysgerrighed

Fordi du ikke VÆLGER det element, du grupperer EFTER. Hvis du sagde:

GROUP BY c.printable_name

Du ville få det forventede NULL. Men du grupperer efter en anden kolonne, så MySQL ved ikke, at printable_name deltager i en opsamlingsgruppe, og vælger en hvilken som helst gammel værdi fra den kolonne i sammenføjningen af ​​alle registreringer. (Så det er muligt, at du vil se andre lande end Usbekistan.)

Dette er en del af et bredere problem med, at MySQL er eftergivende over for, hvad du kan VÆLGE i en GROUP BY-forespørgsel. Du kan f.eks. sige:

SELECT gender FROM registrations GROUP BY country;

og MySQL vil med glæde vælge en af ​​kønsværdierne for en registrering fra hvert land, selvom der ikke er nogen direkte årsagssammenhæng (aka "funktionel afhængighed") mellem land og køn. Andre DBMS'er vil afvise ovenstående kommando med den begrundelse, at der ikke er garanteret ét køn pr. land.(*)

Nu dette:

SELECT c.printable_name AS 'Country', count(*) AS '#' 
FROM registrations r 
INNER JOIN country c ON r.country = c.country_id 
GROUP BY country

er OK, fordi der er en funktionel afhængighed mellem r.country og c.printable_name (forudsat at du har beskrevet dit country_id korrekt som en PRIMÆR NØGLE).

Men MySQL's WITH ROLLUP-udvidelse er lidt af et hack i den måde, det fungerer på. På oprulningsrækkestadiet til sidst kører den over hele præ-grupperingsresultatsættet for at få fat i dets værdier, og derefter indstiller gruppe-efter-kolonnen til NULL. Det nulstiller ikke også andre kolonner, der har en funktionel afhængighed af den pågældende kolonne. Det burde det nok, men MySQL forstår i øjeblikket ikke rigtig det hele om funktionelle afhængigheder.

Så hvis du vælger c.printable_name, vil det vise dig, hvilken landenavnsværdi den tilfældigt valgte, og hvis du vælger c.country_id, vil den vise dig hvilket lande-id den tilfældigt valgte — selvom c.country_id er tilfældighedskriteriet, så skal det være det samme som r.country, som er NULL!

Hvad du kan gøre for at omgå problemet er:

  • grupper efter printbart_navn i stedet for; skal være OK, hvis printbare_navne er unikke, eller
  • vælg "r.land" samt udskrivbart_navn, og tjek, at det er NULL, eller
  • glem MED ROLLUP og lav en separat forespørgsel for slutsummen. Dette vil være lidt langsommere, men det vil også være ANSI SQL-92-kompatibelt, så din app kan fungere på andre databaser.

(*:MySQL har en SQL_MODE-indstilling ONLY_FULL_GROUP_BY det formodes at løse dette problem, men det går alt for vidt og lader dig kun vælge kolonner fra GROUP BY, ikke kolonner, der har en funktionel afhængighed af GROUP BY. Så det vil også få gyldige forespørgsler til at mislykkes, hvilket gør det generelt ubrugeligt.)



  1. Vores nye SQLPerformance.com nyhedsbrev

  2. Sådan opretter du PDF-rapport ved hjælp af PL/SQL

  3. Sådan finder du ikke-numeriske værdier i en kolonne i MySQL

  4. SQL-antal - virker ikke