sql >> Databasteknik >  >> RDS >> Mysql

MySQL:Total GROUP BY WITH ROLLUP nyfikenhet

Eftersom du inte VÄLJER objektet som du grupperar EFTER. Om du sa:

GROUP BY c.printable_name

Du skulle få den förväntade NULL. Men du grupperar efter en annan kolumn så MySQL vet inte att printable_name deltar i en samlingsgrupp och väljer ett gammalt värde från den kolumnen, i sammanfogningen av alla registreringar. (Så det är möjligt att du kommer att se andra länder än Uzbekistan.)

Detta är en del av ett större problem med att MySQL är tillåtande för vad du kan VÄLJA i en GROUP BY-fråga. Du kan till exempel säga:

SELECT gender FROM registrations GROUP BY country;

och MySQL väljer gärna ett av könsvärdena för en registrering från varje land, även om det inte finns något direkt orsakssamband (aka "funktionellt beroende") mellan land och kön. Andra DBMS:er kommer att vägra kommandot ovan på grund av att det inte garanterat finns ett kön per land.(*)

Nu, detta:

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

är OK, eftersom det finns ett funktionellt beroende mellan r.country och c.printable_name (förutsatt att du korrekt har beskrivit ditt country_id som en PRIMÄRNYCKEL).

Men MySQL's WITH ROLLUP-tillägget är lite av ett hack i hur det fungerar. På sammanställningsraden i slutet kör den över hela resultatuppsättningen för förgruppering för att ta tag i dess värden och sedan ställer in gruppvis-kolumnen till NULL. Det nullar inte också andra kolumner som har ett funktionellt beroende av den kolumnen. Det borde det förmodligen, men MySQL förstår för närvarande inte riktigt hela grejen om funktionella beroenden.

Så om du väljer c.printable_name kommer det att visa dig vilket landsnamn det valde slumpmässigt, och om du väljer c.country_id kommer det att visa dig vilket lands-ID det valde slumpmässigt —  även om c.country_id är anslutningskriteriet, så måste det vara samma som r.country, som är NULL!

Vad du kan göra för att komma runt problemet är:

  • gruppera efter utskrivbart_namn istället; ska vara OK om utskrivbara_namn är unika, eller
  • välj "r.land" samt utskrivbart_namn och kontrollera att det är NULL, eller
  • glöm MED ROLLUP och gör en separat fråga för slutsumman. Detta kommer att vara lite långsammare men det kommer också att vara ANSI SQL-92-kompatibelt så att din app kan fungera på andra databaser.

(*:MySQL har ett SQL_MODE-alternativ ONLY_FULL_GROUP_BY det är tänkt att lösa detta problem, men det går alldeles för långt och låter dig bara välja kolumner från GROUP BY, inte kolumner som har ett funktionellt beroende av GROUP BY. Så det kommer att göra att giltiga frågor misslyckas också, vilket gör den generellt värdelös.)



  1. sqliteLog 14:kan inte öppna filen på rad

  2. Fyll i saknade datum för SQL Server Query Output med CTE

  3. Säkerhetskopiera databas i MySQL med C#

  4. Ogiltigt parameternummer:antalet bundna variabler matchar inte antalet tokens i Doctrine