sql >> Database >  >> RDS >> Mysql

MySQL:Total GROUP BY MET ROLLUP nieuwsgierigheid

Omdat u het item waarop u GROUPERT niet SELECTEERT. Als je zei:

GROUP BY c.printable_name

Je zou de verwachte NULL krijgen. Je groepeert echter op een andere kolom, zodat MySQL niet weet dat printable_name deelneemt aan een rollup-groep, en selecteert een oude waarde uit die kolom, in de samenvoeging van all registraties. (Het is dus mogelijk dat u andere landen ziet dan Oezbekistan.)

Dit maakt deel uit van een breder probleem waarbij MySQL toelaatbaar is voor wat u kunt SELECTEREN in een GROUP BY-query. U kunt bijvoorbeeld zeggen:

SELECT gender FROM registrations GROUP BY country;

en MySQL kiest graag een van de geslachtswaarden voor een registratie uit elk land, ook al is er geen direct causaal verband (ook bekend als "functionele afhankelijkheid") tussen land en geslacht. Andere DBMS'en zullen het bovenstaande commando weigeren omdat er niet gegarandeerd is dat er één geslacht per land is.(*)

Nu, dit:

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

is OK, omdat er een functionele afhankelijkheid is tussen r.country en c.printable_name (ervan uitgaande dat je je country_id correct hebt beschreven als een PRIMAIRE SLEUTEL).

De WITH ROLLUP-extensie van MySQL is echter een beetje een hack in de manier waarop het werkt. In de rollup-rijfase aan het einde loopt het over de hele pre-groeperingsresultatenset om de waarden te pakken, en vervolgens stelt de kolom group-by in op NULL. Het maakt ook geen nul voor andere kolommen die een functionele afhankelijkheid van die kolom hebben. Waarschijnlijk zou dat wel moeten, maar MySQL begrijpt momenteel niet echt alles over functionele afhankelijkheden.

Dus als je c.printable_name selecteert, wordt de landnaam die het willekeurig heeft gekozen, getoond en als je c.country_id selecteert, wordt het land-ID weergegeven dat het willekeurig heeft gekozen —  hoewel c.country_id het deelnamecriterium is, moet dat ook zo zijn hetzelfde als r.country, wat NULL is!

Wat u kunt doen om het probleem te omzeilen, is:

  • groepeer in plaats daarvan op afdrukbare_naam; zou OK moeten zijn als printable_names uniek zijn, of
  • selecteer "r.country" evenals printable_name, en controleer of dat NULL is, of
  • vergeet WITH ROLLUP en voer een aparte query uit voor de eindsom. Dit zal iets langzamer zijn, maar het zal ook ANSI SQL-92-compatibel zijn, zodat uw app op andere databases kan werken.

(*:MySQL heeft een SQL_MODE-optie ALLEEN_FULL_GROUP_BY dat zou dit probleem moeten oplossen, maar het gaat veel te ver en laat je alleen kolommen selecteren uit de GROUP BY, geen kolommen die een functionele afhankelijkheid hebben van de GROUP BY. Het zorgt er dus voor dat geldige zoekopdrachten ook mislukken, waardoor het over het algemeen nutteloos wordt.)



  1. Oracle DBA-mentor

  2. Wat is een logische EN-operator in SQL Server - SQL Server / TSQL-zelfstudiedeel 120

  3. SEC_TO_TIME() Voorbeelden – MySQL

  4. Mysql - Mysql2::Fout:Onjuiste tekenreekswaarde: