sql >> Databáze >  >> RDS >> Mysql

MySQL:Total GROUP BY S ROLLUP zvědavostí

Protože nevybíráte položku, podle které seskupujete. Pokud jste řekli:

GROUP BY c.printable_name

Dostanete očekávanou hodnotu NULL. Vy však seskupujete podle jiného sloupce, takže MySQL neví, že printable_name se účastní kumulativní skupiny, a vybere jakoukoli starou hodnotu z tohoto sloupce ve spojení all registrace. (Je tedy možné, že uvidíte i jiné země než Uzbekistán.)

To je součástí širšího problému s MySQL, který je tolerantní k tomu, co můžete VYBRAT v dotazu GROUP BY. Můžete například říct:

SELECT gender FROM registrations GROUP BY country;

a MySQL s radostí vybere jednu z hodnot pohlaví pro registraci z každé země, i když mezi zemí a pohlavím neexistuje žádná přímá příčinná souvislost (neboli „funkční závislost“). Ostatní DBMS odmítnou výše uvedený příkaz s odůvodněním, že není zaručeno, že v každé zemi bude jedno pohlaví.(*)

Nyní toto:

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

je v pořádku, protože mezi r.country a c.printable_name existuje funkční závislost (za předpokladu, že jste správně popsali své country_id jako PRIMÁRNÍ KLÍČ).

Rozšíření WITH ROLLUP MySQL je však trochu hack ve způsobu, jakým funguje. Ve fázi souhrnného řádku na konci přejde přes celou sadu výsledků předběžného seskupení, aby získal její hodnoty a pak nastaví sloupec podle skupiny na hodnotu NULL. Nevynuluje také ostatní sloupce, které jsou na daném sloupci funkčně závislé. Pravděpodobně by mělo, ale MySQL v současné době ve skutečnosti nerozumí celé věci o funkčních závislostech.

Pokud tedy vyberete c.printable_name, zobrazí se vám jakákoli hodnota názvu země, kterou náhodně vybral, a pokud vyberete možnost c.country_id, zobrazí se vám libovolné ID země, které náhodně vybral — i když je c.country_id kritériem pro připojení, musí být stejně jako r.country, což je NULL!

Problém můžete obejít takto:

  • místo toho seskupit podle printable_name; by mělo být v pořádku, pokud jsou printable_names jedinečné, nebo
  • vyberte „r.country“ a také printable_name a zkontrolujte, zda je NULL, nebo
  • zapomeňte na WITH ROLLUP a proveďte samostatný dotaz na konečný součet. Bude to trochu pomalejší, ale bude to také kompatibilní s ANSI SQL-92, takže vaše aplikace bude fungovat i v jiných databázích.

(*:MySQL má možnost SQL_MODE ONLY_FULL_GROUP_BY to by mělo tento problém vyřešit, ale jde to příliš daleko a umožňuje vám vybrat pouze sloupce ze skupiny GROUP BY, nikoli sloupce, které mají funkční závislost na GROUP BY. Takže to způsobí, že platné dotazy selžou také, takže to bude obecně k ničemu.)



  1. Příklady MONTH() v SQL Server (T-SQL)

  2. Získejte první pondělí v měsíci v SQLite

  3. Chyba mySQL 1040:Příliš mnoho připojení

  4. Termín syntaxe SQL pro 'WHERE (sloupec1, sloupec2) <(hodnota1, hodnota2)'