sql >> Database >  >> RDS >> Mysql

Hoe GROUP BY op de juiste manier in MySQL?

Het eerste dat duidelijk moet worden gemaakt, is dat SQL geen MySQL is.

In standaard SQL is het niet toegestaan ​​om te groeperen op een subset van de niet-geaggregeerde velden. De reden is heel eenvoudig. Stel dat ik deze zoekopdracht uitvoer:

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

Die vraag zou geen zin hebben. Zelfs proberen het uit te leggen zou onmogelijk zijn. Het is zeker kleuren selecteren en het aantal auto's per kleur tellen. Het voegt echter ook de owner_name . toe veld en er kunnen veel eigenaren zijn voor een bepaalde kleur, zoals het geval is voor de White kleur. Dus als er veel owner_name . kunnen zijn waarden voor een enkele color wat toevallig het enige veld is in de GROUP BY clausule... welke owner_name zal worden geretourneerd?

Als het nodig is om een ​​owner_name te retourneren dan moeten er een soort criteria worden toegevoegd om er slechts één te selecteren, bijvoorbeeld de eerste alfabetisch, in dit geval John . Die criteria zouden resulteren in het toevoegen van een aggregatiefunctie MIN(owner_name) en dan is de query weer logisch omdat deze wordt gegroepeerd op ten minste alle niet-geaggregeerde velden in de select-instructie.

Zoals u kunt zien, is er een duidelijke en praktische reden waarom standaard-SQL niet flexibel is in de groepering. Als dat niet het geval was, zou u te maken kunnen krijgen met lastige situaties waarin de waarde van een kolom onvoorspelbaar is, en dat is geen aardig woord, vooral niet als de query die wordt uitgevoerd uw bankrekeningtransacties laat zien.

Dat gezegd hebbende, waarom zou MySQL dan query's toestaan ​​die misschien niet logisch zijn? En erger nog, de fout in de bovenstaande query kan gewoon syntactisch worden gedetecteerd! Het korte antwoord is:prestatie. Het lange antwoord is dat er bepaalde situaties zijn waarin, op basis van datarelaties, het krijgen van een onvoorspelbare waarde van de groep zal resulteren in een voorspelbare waarde.

Als je het nog niet door hebt, is de enige manier waarop je de waarde kunt voorspellen die je krijgt als je een onvoorspelbaar element uit een groep neemt, als alle elementen in de groep hetzelfde zijn. Een duidelijk voorbeeld van deze situatie is in de voorbeeldquery in dezelfde vraag. Kijk hoe owner_id en owner_name betreft in de tabel. Het is duidelijk dat gegeven een owner_id , bijv. 2 , je kunt maar één duidelijke owner_name . hebben . Zelfs als je veel rijen hebt, krijg je door er een te kiezen Mike als resultaat. In formeel databasejargon kan dit worden uitgelegd als owner_id bepaalt functioneel owner_name .

Laten we die volledig werkende MySQL-query eens nader bekijken:

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

Gegeven een owner_id dit zou dezelfde owner_name teruggeven , dus voeg het toe aan de GROUP BY clausule zal niet resulteren in meer geretourneerde rijen. Zelfs het toevoegen van een geaggregeerde functie MAX(owner_name) resulteert niet in minder geretourneerde rijen. De resulterende gegevens zullen exact hetzelfde zijn. In beide gevallen zou de query onmiddellijk worden omgezet in een juridische standaard SQL-query, aangezien ten minste alle niet-geaggregeerde velden zouden worden gegroepeerd op. Er zijn dus 3 benaderingen om dezelfde resultaten te krijgen.

Zoals ik eerder al zei, heeft deze niet-standaard groepering echter een prestatievoordeel. Je kunt deze zo onderschatte link bekijken waarin dit wordt uitgelegd voor meer detail, maar ik ga het belangrijkste deel noemen:

Een ding dat het vermelden waard is, is dat de resultaten niet per se fout zijn maar eerder onbepaald . Met andere woorden, het verkrijgen van de verwachte resultaten betekent niet dat u de juiste zoekopdracht hebt geschreven. Het schrijven van de juiste zoekopdracht geeft u altijd de verwachte resultaten.

Zoals je kunt zien, is het misschien de moeite waard om deze MySQL-extensie toe te passen op de GROUP BY clausule. Hoe dan ook, als dit nog niet 100% duidelijk is, is er een vuistregel die ervoor zorgt dat je groepering altijd correct zal zijn:Altijd groeperen, tenminste, op alle niet-geaggregeerde velden in de select-clausule . In bepaalde situaties verspil je misschien een paar CPU-cycli, maar het is beter dan onbepaald terug te sturen resultaten. Als je nog steeds bang bent om niet correct te groeperen, verander dan de ONLY_FULL_GROUP_BY SQL-modus kan een laatste redmiddel zijn :)

Moge uw groepering correct en performant zijn... of op zijn minst correct.




  1. doctrine - krijg volgende en vorige record

  2. Hoe de Meridiem Indicator (AM/PM) toe te voegen aan een tijdwaarde in Oracle

  3. Een probleem hebben met het binden van parameters aan een PDO-instructie

  4. een Unicode-teken in databsae invoegen