sql >> Databasteknik >  >> RDS >> Mysql

Hur man korrekt GROUP BY i MySQL?

Det första att göra klart är att SQL inte är MySQL.

I standard SQL är det inte tillåtet att gruppera efter en delmängd av de icke aggregerade fälten. Anledningen är väldigt enkel. Anta att jag kör den här frågan:

SELECT color, owner_name, COUNT(*) FROM cars
GROUP BY color

Den frågan skulle inte ge någon mening. Att ens försöka förklara det skulle vara omöjligt. Visst är det att välja färger och räkna antalet bilar per färg. Men det lägger också till owner_name och det kan finnas många ägare för en given färg, eftersom det är fallet med White Färg. Så om det kan finnas många owner_name värden för en enda color vilket råkar vara det enda fältet i GROUP BY klausul... sedan vilken owner_name kommer att returneras?

Om det behövs för att returnera ett owner_name då bör någon sorts kriterier läggas till för att bara välja ett av dem, t.ex. det första alfabetiskt, vilket i det här fallet skulle vara John . Det kriteriet skulle resultera i att en aggregerad funktion MIN(owner_name) läggs till och då blir frågan meningsfull igen eftersom den kommer att grupperas efter åtminstone alla icke-aggregerade fält i select-satsen.

Som du kan se finns det en tydlig och praktisk anledning till att standard SQL är oflexibel i grupperingen. Om det inte var det, kan du ställas inför besvärliga situationer där värdet för en kolumn kommer att vara oförutsägbart, och det är inte ett bra ord, särskilt om frågan som körs visar dig dina bankkontotransaktioner.

Med det sagt, varför skulle MySQL tillåta frågor som kanske inte är vettiga? Och ännu värre, felet i frågan ovan kunde bara syntaktiskt upptäckas! Det korta svaret är:prestanda. Det långa svaret är att det finns vissa situationer där, baserat på datarelationer, att få ett oförutsägbart värde från gruppen kommer att resultera i ett förutsägbart värde.

Om du inte har räknat ut det än, är det enda sättet på vilket du kan förutsäga värdet du får av att ta ett oförutsägbart element från en grupp om alla element i gruppen är desamma. Ett tydligt exempel på denna situation finns i exempelfrågan i din fråga. Titta på hur owner_id och owner_name avser i tabellen. Det är tydligt att givet någon owner_id , t.ex. 2 , du kan bara ha ett distinkt owner_name . Även om du har många rader, genom att välja någon, får du Mike som resultat. I formell databasjargong kan detta förklaras som owner_id bestämmer funktionellt owner_name .

Låt oss ta en närmare titt på den fullt fungerande MySQL-frågan:

SELECT owner_id, owner_name, COUNT(*) total FROM cars
GROUP BY owner_id

Givet någon owner_id detta skulle returnera samma owner_name , så lägg till den i GROUP BY klausul kommer inte att resultera i att fler rader returneras. Till och med lägga till en aggregerad funktion MAX(owner_name) kommer inte att resultera i att färre rader returneras. Den resulterande informationen kommer att vara exakt densamma. I båda fallen skulle frågan omedelbart omvandlas till en juridisk standard SQL-fråga eftersom åtminstone alla icke-aggregerade fält skulle grupperas efter. Så det finns tre metoder för att få samma resultat.

Men som jag nämnde tidigare har denna icke-standardiserade gruppering en prestandafördel. Du kan kolla den här så underskattade länken där detta förklaras för mer detaljer, men jag kommer att citera den viktigaste delen:

En sak som är värd att nämna är att resultaten inte nödvändigtvis är fel utan snarare obestämd . Med andra ord, att få de förväntade resultaten betyder inte att du har skrivit rätt fråga. Att skriva rätt fråga ger dig alltid de förväntade resultaten.

Som du kan se kan det vara värt att tillämpa detta MySQL-tillägg på GROUP BY klausul. Hur som helst, om detta inte är 100 % tydligt än så finns det en tumregel som säkerställer att din gruppering alltid kommer att vara korrekt:Gruppera alltid, åtminstone, efter alla icke aggregerade fält i select-satsen . Du kanske slösar bort några CPU-cykler i vissa situationer, men det är bättre än att returnera obestämd resultat. Om du fortfarande är livrädd för att inte gruppera korrekt kan du ändra ONLY_FULL_GROUP_BY SQL-läge kan vara en sista utväg :)

Må din gruppering vara korrekt och prestanda... eller åtminstone korrekt.




  1. Hur släpper man unikt i MySQL?

  2. Konfigurationssystemet kunde inte initieras

  3. Hur man anger sorteringen i en fråga i SQL Server (T-SQL)

  4. Ändra en MySQL-kolumn till AUTO_INCREMENT