‘Group by’ statement in MySQL

Na joinen in mysql haal ik een tweede interessante techniek aan die meer dan handig kan gecombineerd worden met joinen tot nog snellere en betere resultaten. Ik leg eerst het principe uit zonder daarbij een join (of meerdere tabellen) te gebruiken, daarna combineer ik de technieken. Group by is gemaakt om een deel van rijen uit een tabel samen te nemen op basis van de gelijkenis van 1 veld en zo groepen te vormen. Je kan dan nog bepaalde beperkingen opleggen op die groepen zodat je echt specifieke rijen uit de database kan halen, maar daarover verder meer. Ik gebruik ook in deze tutorial een voorbeeld. Ik schets de gebruikte tabellen even hieronder. Deze zijn net dezelfde als in de tutorial voor joinen.

Ik denk dat de structuur wel duidelijk is. Zoniet verwijs ik u door naar m’n vorige tutorial. Verder wil ook nog even wijzen op het bestaan van mysql.exe, een programma waarin je doormiddel van een DOS-achtige prompt rechtstreeks op de database kan werken. Om deze te open ga je naar de map waarin mysql is geïnstalleerd, dan naar de map bin en daarin staat het programma. Ik geef toe dat dit minder gebruiksvriendelijk is dan phpmyadmin, maar je kan wel meteen je query’s testen.

Group By
Ik werk even verder op de tabel reactie. Wil je nu bijvoorbeeld alle reacties ophalen op bericht 5, dan doe je dat gewoon met een where clausule:
SELECT * FROM Reac t i e W HERE Did = 5 ;

Wil je nu echter weten hoeveel reacties er waren per bericht, dan gebruik je group by:
SELECT Did , count ( I d ) “aanta l _ reac t i es” FROM Reac t i e GROUP BY Did ;

En dit kan erg handig zijn om een overzicht te geven van alle berichten met daarbij het aantal reacties. Waarin ik de kolom met de telling hernoem naar “aantal_reacties”. Deze hernoeming kan je ook gebruiken in je array, na mysql_fetch_array. Vermijd hierbij wel spaties, want daarop crasht de php-parser. Je merkt metteen dat group by statements handig zijn in combinatie met analytische functies. Zonder deze functies is group by vrijwel nutteloos. Even een opsomming van de meest gebruikte: o Sum() : welke een som geeft van de velden o Avg() : geeft het gemiddelde terug o Max() : geeft het maximum terug o Min() : inderdaad, het minimum o Count() : tellen van aantal bestaande rijen Zo kan je bijvoorbeeld voor elk bericht uit de database de laatste reactie gaan selecteren doormiddel van max(), in de veronderstelling dat de reactie met het hoogste id, de laaste is.
SELECT Did, max(Id) “id_laatste_reactie” FROM Reactie GROUP BY Did;

Jammer genoeg kan je nu met deze query niet de rest van de informatie ophalen van die laatste reactie. Dit kan wel zeer eenvoudig doormiddel van een inner select. Zeg maar een tweede select in deze query, ik ga hier niet verder op in in deze tutorial. Nu we het toch min of meer over analytische functies hebben, wil ik er even op hameren dat je deze NIET kan gebruiken in een where clausule. Je hoeft dus niet te proberen het bericht met de hoogste id op te halen met een query als:
SELECT * FROM Reactie WHERE Id = max(Id);

Dit werkt, nogmaals, niet. Wil je toch dit resultaat verkrijgen, dan zal je met een inner select moeten werken.

having
Je kan een analytische functie wél gaan gebruiken in een having clausule. Zeg maar een voorwaarde op een groep. Deze komt achter de group by clausule. Ik geef een voorbeeld waarin we enkel de berichten weergeven waarop meer dan 10 keer gereageerd is:
SELECT Did, count(Id) “aantal_reacties” FROM Reactie GROUP BY Did HAVING count(Id) > 10;

Hierbij geldt de voorwaarde voor de gehele groep. Wanneer de voorwaarde geldt voor iedere rij apart, gebruik dan where. Zo breid ik vorige query uit tot berichten waarop meer dan 10 reacties zijn en die geschreven zijn door ‘eskimologie’:
SELECT Did, count(Id) “aantal_reacties” FROM Reactie GROUP BY Did HAVING count(Id) > 10 WHERE Naam = ‘eskimologie’;

Het feit dat de bericht door eskimologie geschreven zijn, kan gecontroleerd worden voor iedere rij apart. Het feit of er meer dan 10 berichten zijn, is een voorwaarde over meerdere rijen, vandaar de having.

join
Nu wordt het pas écht interessant wanneer we deze wetenschap combineren met joinen. Lees hiervoor eerst mijn vorige tutorial. Ik zou zeer gemakkelijk alle berichten kunnen ophalen met daarbij een kolom met het aantal reacties in. De query ziet er alsvolgt uit:
SELECT b.Titel, b.Bericht, count(r.Id) FROM Bericht AS b LEFT OUTER JOIN Reactie AS r ON b.Id = r.Did GROUP BY b.Id;

Ook hier is het nodig een outer join te gebruiken om zo zeker alle berichten weer te geven. Ook diegene waarop nog niet gereageerd werd. Om dan nu nog bij wijze van slot alles te combineren nog even het voorbeeld waarin de berichten worden opgehaald, daarbij de naam en email van de schrijver en het aantal reacties. Deze query is nu uitermate interessant om gegevens op te halen voor een overzichtspagina. En dit alles doormiddel van juist 1 query.
SELECT b.Titel, FROM Bericht AS LEFT OUTER JOIN LEFT OUTER JOIN GROUP BY b.Id; b.Bericht, l.Naam, l.Email, count(r.Id) b Reactie AS r ON b.Id = r.Did Lid AS l ON b.Schrijver = l.Lidnr

Voila, bij deze. Wil je deze kolommen nu gebruiken in een php script, zal je ofwel de kolommen even moeten hernoemen want met die count krijg je meestal problemen in een array. Je kan natuurlijk ook nog altijd gewoon een row maken met een array die een numerieke sleutel heeft. (mysql_fetch_row()) Ik hoop bij deze dat er u weer wat duidelijk wordt in de uitgebreide mysql-wereld. Misschien dat je volgende keer je query’s wat meer groepeert, zodat je veel efficiënter kan werken. Veel succes!

Master your semester with Scribd & The New York Times

Special offer for students: Only $4.99/month.

Master your semester with Scribd & The New York Times

Cancel anytime.