SQL GROUP BY: aggregatie en groepering
BeginnerLes 4 van 6 in SQL: de basis
Wat je leert
- Gebruik COUNT, SUM, AVG, MIN en MAX om veel rijen samen te vatten in waarden, kies de juiste manier van tellen en voorspel hoe ontbrekende waarden een resultaat veranderen.
- Bepaal totalen, gemiddelden en de kleinste en grootste waardenGebruik SUM, AVG, MIN en MAX op een hele tabel of op de rijen die een WHERE-clausule behoudt en combineer meerdere functies in één query.
- Tel rijen, waarden en unieke waardenKies tussen COUNT(*), COUNT(column) en COUNT(DISTINCT column) en weet hoe elk omgaat met herhaalde en ontbrekende waarden.
- Voorspel hoe NULL-waarden aggregaties beïnvloedenWeet dat aggregatiefuncties NULL-waarden overslaan, voorspel de resultaten bij lege invoer en vervang NULL door een standaardwaarde als de vraag daarom vraagt.
- Bepaal totalen, gemiddelden en de kleinste en grootste waarden
- Gebruik GROUP BY voor één samenvattende rij per categorie, per combinatie van waarden of per berekende waarde en pas de groeperingsregel toe op de uitvoer van een gegroepeerde query.
- Vat elke categorie samen met GROUP BYVerdeel een tabel in groepen met dezelfde waarde, bereken aggregaties per groep en sorteer en beperk het gegroepeerde resultaat.
- Pas de groeperingsregel toe op de uitvoer van een gegroepeerde queryWeet welke kolommen in de SELECT-lijst van een gegroepeerde query mogen voorkomen, herstel de fout die ontstaat als de regel wordt overtreden en herken hoe databases verschillen.
- Groepeer op meerdere kolommen en op berekende waardenGroepeer rijen op combinaties van kolommen en op expressies zoals de maand van een datum of een CASE-categorie, en lees het gedetailleerdere resultaat.
- Vat elke categorie samen met GROUP BY
- Behoud alleen de groepen waarvan de totalen, aantallen of gemiddelden aan een voorwaarde voldoen en bepaal of een voorwaarde in WHERE of in HAVING hoort.
- Behoud de groepen die aan een voorwaarde voldoenSchrijf HAVING-voorwaarden op aggregatiewaarden, ook op aggregaties die niet worden weergegeven, om een gegroepeerd resultaat te filteren.
- Kies tussen WHERE en HAVINGGebruik de logische volgorde van een query om te bepalen of een voorwaarde rijen of groepen filtert en voorspel hoe die keuze het resultaat verandert.
- Behoud de groepen die aan een voorwaarde voldoen
- Voorkom gehele deling, weet welk type getal elke aggregatiefunctie teruggeeft en rond gemiddelden, totalen en percentages op het juiste moment af.
- Voorkom gehele deling bij gemiddelden en percentagesHerken wanneer bij het delen van aggregatieresultaten de decimalen verloren gaan, los dit op met een decimale operand en weet hoe resultaattypen tussen databases verschillen.
- Rond geaggregeerde resultaten afRond gemiddelden, totalen en percentages af met ROUND, rond op het juiste moment af en houd rekening met de verschillen tussen SQLite en PostgreSQL.
- Voorkom gehele deling bij gemiddelden en percentages
- Combineer CASE met aggregatiefuncties voor voorwaardelijke tellingen, totalen en percentages en zet een vraag om in een gegroepeerde query waarvan je de getallen kunt controleren.
- Tel en sommeer onder voorwaarden met CASEPlaats een CASE-expressie binnen een aggregatiefunctie om meerdere voorwaardelijke tellingen, totalen en percentages in één gegroepeerde query te berekenen.
- Stel op basis van een vraag een aggregatiequery op en controleer dezeZet een bedrijfsvraag stap voor stap om in een gegroepeerde query, voorkom dat je detailniveaus verwart en controleer of de getallen kloppen.
- Tel en sommeer onder voorwaarden met CASE
SQL GROUP BY: uitleg
1Vat gegevens samen met aggregatiefuncties
Een tabel legt afzonderlijke gebeurtenissen vast; een rapport heeft vaak enkele getallen nodig die ze samen beschrijven. Aggregatiefuncties zetten rijen om in aantallen, totalen, gemiddelden en uiterste waarden. De functie kiezen is maar een deel van het werk: je moet ook bepalen welke rijen in de berekening horen en wat ontbrekende waarden betekenen. We gebruiken een kleine besteltabel om elk antwoord met de hand te controleren voordat we op de query vertrouwen.
1.1 Bepaal totalen, gemiddelden en de kleinste en grootste waarden
Een aggregatiefunctie combineert waarden uit meerdere rijen tot één resultaat. Oracle noemt dit ook een groepsfunctie. Zonder GROUP BY behandelt een aggregatiequery alle rijen die aan WHERE voldoen als één groep en geeft één samenvattende rij terug.
Begin met gegevens die je kunt controleren
Elke rij in orders is één bestelling. De numerieke kolommen hieronder bevatten gehele getallen; order_id is de primaire sleutel. Datums gebruiken ISO-tekst in SQLite en het DATE-gegevenstype in PostgreSQL.
| order_id | customer | region | amount | quantity | discount | order_date |
|---|---|---|---|---|---|---|
| 1 | Ana | East | 120 | 2 | 10 | 2026-01-05 |
| 2 | Ben | West | 80 | 1 | NULL | 2026-01-17 |
| 3 | Ana | East | 45 | 3 | 5 | 2026-02-02 |
| 4 | Chen | North | 200 | 4 | NULL | 2026-02-14 |
| 5 | Ben | West | 60 | 1 | 0 | 2026-02-20 |
| 6 | Dara | East | 95 | 2 | NULL | 2026-03-03 |
| 7 | Chen | North | 150 | 5 | 15 | 2026-03-09 |
| 8 | Eli | NULL | 30 | 1 | NULL | 2026-03-21 |
Kies het kengetal
SUM(amount) telt de bedragen op. AVG(amount) geeft hun rekenkundig gemiddelde. MIN(amount) vindt het kleinste bedrag en MAX(amount) het grootste. Je kunt alle vier in één query opvragen:
SELECT SUM(amount) AS total, AVG(amount) AS avg_amount, MIN(amount) AS smallest, MAX(amount) AS largest FROM orders;
Het resultaat is één rij: totaal 780, gemiddelde 97,5, kleinste 30 en grootste 200. Tel de acht bedragen op voor 780 en deel daarna door acht voor 97,5. Elke functie gebruikt dezelfde acht invoerrijen. Duidelijke aliassen na AS maken de uitvoerkoppen bruikbaar; een gegenereerde kop zoals sum zegt weinig over wat is opgeteld.
Filter vóór het berekenen
Om bestellingen uit East samen te vatten, schrijf je SELECT COUNT(*) AS orders, SUM(amount) AS total FROM orders WHERE region = 'East';. Het filter behoudt de bedragen 120, 45 en 95. De query geeft drie bestellingen en een totaal van 260 terug. WHERE kiest de invoerrijen voordat een aggregatiefunctie wordt toegepast.
Een aggregatiefunctie kan ook een berekende expressie als argument hebben. In een tabel met quantity en unit_price bepaalt SUM(quantity * unit_price) eerst de omzet per rij en telt die daarna op. Twee rijen, twee artikelen van 5 en drie artikelen van 10, dragen 10 en 30 bij, samen 40. SUM(quantity) * SUM(unit_price) vermenigvuldigt daarentegen 5 met 15 en geeft 75. Door de berekening binnen SUM te houden, blijft elk aantal gekoppeld aan de bijbehorende prijs.
Lees uiterste waarden correct
MIN(order_date) is 2026-01-05 en MAX(order_date) is 2026-03-21. Datumwaarden en ISO-datumtekst worden chronologisch gesorteerd. Tekst zoals “03/21/2026” volgt de tekenvolgorde, die niet altijd overeenkomt met de datumvolgorde. Uiterste tekstwaarden volgen ook de sorteerregels van de database: de regels voor het vergelijken van tekst. Hier zijn de uiterste klantnamen “Ana” en “Eli”; een combinatie van hoofdletters en kleine letters kan de tekstvolgorde veranderen.
MAX(amount) geeft een bedrag terug, niet de hele bestelling die het bevat. Om een klant met een grootste bestelling te tonen, gebruik je SELECT customer, amount FROM orders ORDER BY amount DESC LIMIT 1;. PostgreSQL weigert een gewone customer naast MAX(amount) zonder een passende groepering. SQLite heeft een speciale regel voor één MIN of MAX die een andere kolom uit de rij met de uiterste waarde kan teruggeven, maar bij gelijke uiterste waarden is nog steeds een regel nodig om de volgorde te bepalen.
Belangrijkste punten
- Een aggregatiefunctie geeft één waarde terug voor een verzameling rijen.
WHEREselecteert de rijen die de aggregatiefunctie gebruikt.- Bereken de bijdrage van elke rij binnen
SUMwanneer waarden gekoppeld moeten blijven. MINenMAXvolgen de volgorde van getallen, datums of tekst.- Een uiterste waarde identificeert geen volledige rij.
1.2 Tel rijen, waarden en unieke waarden
“Hoeveel?” kan vragen naar rijen, vastgelegde waarden of verschillende waarden. Dat zijn verschillende tellingen, ook als ze in een kleine tabel toevallig hetzelfde aantal opleveren.
Drie vormen van COUNT
| Expressie | Wat wordt geteld |
|---|---|
COUNT(*) | Elke invoerrij |
COUNT(region) | Rijen met een regio die niet NULL is |
COUNT(DISTINCT region) | Verschillende regiowaarden die niet NULL zijn |
In de besteltabel zijn de regio's East, West, East, North, West, East, North en NULL. SELECT COUNT(*) AS order_rows, COUNT(region) AS with_region, COUNT(DISTINCT region) AS regions FROM orders; geeft 8, 7 en 3 terug. De herhaalde regionamen tellen afzonderlijk mee in COUNT(region), maar elke naam draagt slechts eenmaal bij aan de telling van unieke waarden.
Voor “Hoeveel verschillende klanten hebben besteld?” gebruik je COUNT(DISTINCT customer). Ana, Ben en Chen komen elk tweemaal voor, terwijl Dara en Eli eenmaal voorkomen, dus het antwoord is vijf klanten. COUNT(customer) geeft acht terug omdat elke bestelling een klant vermeldt. Het meet bestelrijen met een klantnaam, geen personen.
Een vastgelegde nul telt mee
De kortingen zijn 10, NULL, 5, NULL, 0, NULL, 15 en NULL. COUNT(discount) geeft vier terug. De nul legt een bekende waarde vast en telt net als 10, 5 en 15 mee. Een lege tekenreeks is ook een waarde in SQLite en PostgreSQL; Oracle behandelt een lege tekenreeks als NULL.
Trek de telling van waarden die niet NULL zijn af van het aantal rijen om ontbrekende gegevens te meten: SELECT COUNT(*) - COUNT(region) AS missing_region FROM orders; geeft één terug. Dit werkt omdat beide tellingen precies dezelfde invoerrijen gebruiken.
DISTINCT-lijsten en tellingen van unieke waarden
SELECT DISTINCT region FROM orders; geeft East, West, North en één NULL-rij weer. De taak van deze query is verschillende waarden terug te geven, en NULL blijft in die lijst staan. COUNT(DISTINCT region) geeft drie terug omdat de telling NULL negeert. Leid een telling van unieke waarden niet af door een lijst te tellen voordat je hebt bepaald of de NULL-rij meetelt.
DISTINCT kan ook binnen SUM of AVG staan. De aantallen zijn 2, 1, 3, 4, 1, 2, 5 en 1. Hun gewone som is 19. SUM(DISTINCT quantity) behoudt alleen 1, 2, 3, 4 en 5 en geeft 15. Herhaalde aantallen beschrijven meestal echte extra verkopen. Als je ze verwijdert, verandert het kengetal; je herstelt er geen dubbele records mee.
Tel combinaties in twee stappen
Voor verschillende paren van regio en klant maak je eerst een lijst met unieke combinaties:
SELECT COUNT(*) FROM (SELECT DISTINCT region, customer FROM orders) AS pairs;
De binnenste query geeft vijf paren terug: East/Ana, East/Dara, North/Chen, West/Ben en NULL/Eli. De buitenste COUNT(*) telt die vijf rijen, inclusief NULL/Eli. Deze vorm werkt in SQLite en PostgreSQL. MySQL accepteert ook COUNT(DISTINCT region, customer), maar die vorm sluit combinaties met NULL uit en kan dus een andere vraag beantwoorden. In SQLite en PostgreSQL is de vorm met een komma ongeldig.
Een telling geeft nooit NULL terug. SELECT COUNT(*) FROM orders WHERE region = 'South'; geeft één samenvattende rij met nul terug, omdat er geen overeenkomende bestellingen zijn.
Belangrijkste punten
- Kies tussen rijen, vastgelegde waarden en verschillende vastgelegde waarden.
- Nul is een vastgelegde waarde, dus
COUNT(column)telt die mee. - Een lijst met unieke waarden kan NULL bevatten;
COUNT(DISTINCT column)slaat die over. SUM(DISTINCT x)verwijdert herhaalde waarden, ook terechte herhalingen.- Tel unieke combinaties door een uniek binnenste resultaat te tellen.
COUNTgeeft nul terug bij lege invoer.
1.3 Voorspel hoe NULL-waarden aggregaties beïnvloeden
NULL betekent dat een waarde ontbreekt of onbekend is. Het verandert welke waarden een aggregatiefunctie verwerkt, zodat een totaal of gemiddelde geldige SQL kan zijn maar iets anders kan meten dan je bedoelde.
Bepaal de noemer
Stel dat scores Ana 80, Ben NULL, Chen 70 en Dara 90 bevat. SUM(score) is 240, COUNT(score) is drie en COUNT(*) is vier. AVG(score) is 80: de drie vastgelegde scores tellen op tot 240 en worden gedeeld door drie.
De vijf standaardaggregatiefuncties negeren NULL-argumenten. COUNT(*) telt elke rij omdat deze geen kolomargument evalueert. MIN(score) is 70 en MAX(score) is 90; NULL wordt niet de kleinste of grootste score. Dit verschilt van sorteren, waarbij NULL-waarden aan een uiteinde van het resultaat staan: vooraan bij oplopend sorteren in SQLite, achteraan bij oplopend sorteren in PostgreSQL.
Voor een handmatige berekening van het gemiddelde heb je de telling van waarden nodig die niet NULL zijn: 1.0 * SUM(score) / NULLIF(COUNT(score), 0). De decimale operand behoudt resultaten met decimalen en NULLIF maakt een deler van nul tot NULL. Delen door COUNT(*) zou 60 opleveren en de ontbrekende score feitelijk als nul behandelen.
Bepaal wat een standaardwaarde betekent
COALESCE geeft het eerste argument terug dat niet NULL is. Als Ben nog niet is beoordeeld, laat je de score ontbreken en bereken je het gemiddelde van de bekende resultaten. Als een gemist examen als NULL is vastgelegd maar als nul moet meetellen, berekent AVG(COALESCE(score, 0)) het gemiddelde van 80, 0, 70 en 90, wat 60 oplevert. De betekenis van de gegevens bepaalt of die vervanging terecht is.
Vergelijk COALESCE binnen en buiten een functie. AVG(COALESCE(score, 0)) verandert de waarden die in het gemiddelde komen. COALESCE(AVG(score), 0) verandert alleen een eindresultaat dat NULL is; voor deze scores geeft het nog steeds 80. NVL(x, 0) van Oracle is een andere vorm met twee argumenten om NULL te vervangen.
Maak onderscheid tussen geen rijen en geen vastgelegde waarden
Bij WHERE region = 'South' blijven geen bestellingen over. Een aggregatiequery zonder GROUP BY geeft nog steeds één rij terug: COUNT(*) is nul, terwijl SUM(amount), AVG(amount), MIN(amount) en MAX(amount) NULL zijn. Gebruik COALESCE(SUM(amount), 0) om een leeg totaal als nul weer te geven. SQLite biedt ook TOTAL(amount), dat 0,0 teruggeeft bij lege invoer.
Behoud nu de vier bestellingen waarvan de korting NULL is. Er zijn rijen, maar geen vastgelegde kortingswaarden: COUNT(*) is vier, COUNT(discount) is nul en SUM(discount) is NULL. Nul vastgelegde waarden en vier ontbrekende waarden zijn verschillende waarnemingen.
Controleer expressies voordat ze in SUM komen
Rekenen met NULL levert NULL op. In SUM(amount - discount) dragen de vier bestellingen zonder vastgelegde korting helemaal geen waarde bij. Alleen de rijen met een bekende korting dragen bij: 110, 40, 60 en 135, samen 345.
Als een ontbrekende korting betekent dat er geen korting is, schrijf je SUM(amount - COALESCE(discount, 0)). Elke bestelling draagt dan bij; het totale bedrag van 780 min de vastgelegde kortingen van 30 geeft 750. COALESCE om de hele som heen zetten zou de weggelaten bestellingen niet terugbrengen, omdat 345 al geen NULL is.
Gebruik IS NULL of IS NOT NULL om ontbrekende waarden te vinden. WHERE discount IS NULL vindt vier bestellingen. discount = NULL is nooit waar en kan ze daarom niet selecteren.
Belangrijkste punten
AVG(x)deelt door het aantal waarden dat niet NULL is.- Een
COALESCEbinnen een functie verandert de invoer; een functie eromheen verandert een resultaat dat NULL is. - Lege invoer geeft nul voor
COUNTen NULL voor de andere vier aggregatiefuncties. - NULL binnen een rekenkundige expressie kan de bijdrage van een rij weglaten.
2Groepeer rijen en vat elke groep samen
Een totaal over de hele tabel beantwoordt één vraag, maar veel rapporten vragen om een resultaat per klant, regio of maand. Groeperen stelt dat detailniveau vast voordat de aggregatiefuncties worden toegepast. Je volgt hoe rijen groepen worden, kiest kolommen die een hele groep kunnen beschrijven en ziet hoe een extra groeperingskolom het rapport verandert. Sorteren bepaalt vervolgens hoe je de resultaten presenteert; groeperen alleen geeft ze geen volgorde.
2.1 Vat elke categorie samen met GROUP BY
GROUP BY verzamelt rijen met dezelfde groeperingswaarde. Elke aggregatiefunctie wordt afzonderlijk binnen elke groep toegepast en de uitvoer bevat één rij voor elke groep die na het filteren bestaat.
Bepaal wat één resultaatrij betekent
“Totale omzet per regio” vraagt om één uitvoerrij per regio. Begin met die zin en gebruik vervolgens region als groeperingskolom:
SELECT region, COUNT(*) AS orders, SUM(amount) AS total FROM orders GROUP BY region;
De drie bedragen van East, 120, 45 en 95, worden één groep. Het aantal is drie en het totaal is 260. North heeft twee bestellingen met een totaal van 350; West heeft er twee met een totaal van 140. De bestelling van Eli vormt een NULL-regiogroep met één bestelling van in totaal 30. Er zijn vier resultaatrijen, geen acht.
Lees de query als een reeks stappen: FROM levert bestellingen, een eventuele WHERE verwijdert rijen, GROUP BY verzamelt de resterende rijen per regio en de aggregatiefuncties vatten elke verzameling samen. SELECT geeft het label en de kengetallen weer. Groeperen verwijdert geen kleinere bestellingen binnen een groep; ze dragen allemaal bij, tenzij een rijfilter ze heeft verwijderd.
Houd ontbrekende categorieën zichtbaar
Rijen met NULL in de groeperingskolom behoren tot één NULL-groep. Dat is nuttig: een rapport kan tonen hoeveel activiteit geen vastgelegde regio heeft. Het behandelt niet elke ontbrekende regio als een andere categorie.
Om een leesbaar label te tonen, selecteer je COALESCE(region, 'No region') AS region_label en behoud je GROUP BY region. Het label verandert de weergegeven waarde. Om die rijen uit de berekeningen weg te laten, voeg je WHERE region IS NOT NULL toe vóór GROUP BY. De resulterende totalen tellen op tot 750, omdat het bedrag van 30 van Eli is weggelaten.
Een gegroepeerde query over invoer zonder rijen geeft geen groepen terug. Als je de tabel bijvoorbeeld filtert op South en vervolgens op regio groepeert, geeft dit geen resultaatrijen terug. Dat verschilt van een aggregatie over de hele tabel zonder GROUP BY, die ook bij lege invoer één samenvattende rij oplevert.
Sorteer de groepen expliciet
GROUP BY garandeert geen uitvoervolgorde. Om de grootste regio's eerst weer te geven, voeg je ORDER BY total DESC toe. De alias total is toegestaan in ORDER BY; ORDER BY SUM(amount) DESC geeft dezelfde sortering.
Een klantrapport kan de drie hoogste totalen selecteren:
SELECT customer, SUM(amount) AS total FROM orders GROUP BY customer ORDER BY total DESC, customer LIMIT 3;
Het geeft Chen 350, Ana 165 en Ben 140 terug. De tweede sorteersleutel, customer, geeft gelijke totalen een reproduceerbare volgorde. LIMIT 3 geeft maar drie rijen terug; het behoudt niet alle gelijke waarden op de grens. SQL Server drukt deze beperking uit met SELECT TOP 3, terwijl Oracle FETCH FIRST 3 ROWS ONLY ondersteunt.
Bij het oplopend sorteren van categorielabels plaatst SQLite NULL normaal vooraan en PostgreSQL achteraan. Geef de gewenste volgorde op wanneer de plaats van belang is.
Controleer de groeperingskolom
SELECT DISTINCT region FROM orders en SELECT region FROM orders GROUP BY region geven dezelfde unieke regiolabels terug, inclusief NULL. Gebruik groepering wanneer je ook een kengetal voor elk label nodig hebt.
Groeperen op de unieke order_id geeft acht groepen van elk één rij. Elk aantal is één en elk bedragstotaal is gelijk aan het oorspronkelijke bedrag. Voor een regionaal rapport geeft dat resultaat aan dat de groeperingskolom te gedetailleerd is.
Belangrijkste punten
- Benoem waar één uitvoerrij voor staat voordat je
GROUP BYkiest. - Alle NULL-groeperingswaarden vormen samen één groep.
- Gebruik
ORDER BYvoor de resultaatvolgorde en een tweede sleutel om gelijke waarden te ordenen. - Groeperen op een unieke rijsleutel levert groepen van één rij op.
2.2 Pas de groeperingsregel toe op de uitvoer van een gegroepeerde query
Een gegroepeerd rapport moet veel invoerrijen in één resultaatrij onderbrengen. Elke weergegeven waarde moet daarom een duidelijke betekenis hebben voor de hele groep. Daarom beperkt SQL welke kolommen je kunt selecteren.
Volg de overdraagbare groeperingsregel
Een item in een gegroepeerde SELECT moet een groeperingskolom zijn, een expressie opgebouwd uit groeperingskolommen, een aggregatie of een constante. Bekijk:
SELECT region, customer, COUNT(*) FROM orders GROUP BY region;
East bevat Ana, Ana en Dara. De groep heeft één regio en één aantal, maar twee verschillende klantnamen. De query geeft niet aan welke klant één resultaat voor East moet tonen. PostgreSQL weigert de niet-gegroepeerde kolom customer.
Hetzelfde probleem doet zich voor zonder GROUP BY: SELECT customer, SUM(amount) FROM orders combineert een totaal over de hele tabel met een afzonderlijke naam. Het totaal heeft niet één klant als label.
Pas de query aan de vraag aan
Er zijn drie bruikbare oplossingen, elk met een andere betekenis:
- Verwijder
customervoor één rij per regio:SELECT region, COUNT(*) FROM orders GROUP BY region;. - Groepeer op beide voor één rij per regio en klant:
SELECT region, customer, COUNT(*) FROM orders GROUP BY region, customer;. - Aggregeer de namen voor het aantal klanten per regio:
SELECT region, COUNT(DISTINCT customer) AS customers FROM orders GROUP BY region;.
De laatste query rapporteert twee klanten in East en één in elk van de andere regiogroepen. Een kolom toevoegen aan GROUP BY kan het detailniveau van het rapport veranderen. Kies de oplossing dus op basis van de vraag en niet alleen van de foutmelding.
Een groeperingskolom mag uit SELECT worden weggelaten. SELECT COUNT(*) FROM orders GROUP BY region; is geldig en geeft vier aantallen terug: drie, twee, twee en één, zonder gegarandeerde volgorde. Die getallen zijn lastig te gebruiken zonder hun regiolabels.
Pas de regel ook buiten SELECT toe
Een gegroepeerde ORDER BY customer heeft hetzelfde probleem wanneer alleen op regio wordt gegroepeerd: welke klant moet de positie van East bepalen? Gegroepeerde HAVING-voorwaarden moeten ook een hele groep beschrijven. Gebruik daar gegroepeerde kolommen of aggregatie-expressies.
Herken soepel databasegedrag
SQLite accepteert een niet-gegroepeerde, niet-geaggregeerde kolom: een geselecteerde kolom die niet is gegroepeerd en niet is geaggregeerd. Het neemt een waarde uit één invoerrij van de groep. Een ogenschijnlijk geslaagd resultaat zoals “Ana” naast East betekent niet dat Ana elke bestelling in die regio vertegenwoordigt.
Bij precies één ingebouwde aggregatiefunctie MIN of MAX neemt SQLite zulke waarden uit een rij met de uiterste waarde. Bij gelijke waarden en meerdere aggregatiefuncties voor uiterste waarden is de geselecteerde rij onzeker. Deze verkorte werkwijze is databasespecifiek. De oorspronkelijke rijen sorteren is duidelijker wanneer je een bestelling met een uiterste bedrag zoekt.
De standaardmodus ONLY_FULL_GROUP_BY van MySQL weigert niet-gegroepeerde waarden die niet door de groep worden bepaald. ANY_VALUE(customer) staat expliciet een willekeurige waarde toe, maar vindt niet de klant die bij een gekozen totaal hoort. SQL Server en Oracle weigeren gewone niet-gegroepeerde kolommen ook.
PostgreSQL en MySQL herkennen een uitzondering voor de primaire sleutel: groeperen op de primaire sleutel van een tabel identificeert één rij, zodat de andere kolommen daarvan vastliggen. SELECT order_id, customer, SUM(amount) FROM orders GROUP BY order_id werkt in PostgreSQL. Elke weergegeven gewone kolom in GROUP BY opnemen blijft de overdraagbare aanpak.
Belangrijkste punten
- Elke weergegeven waarde moet de hele groep beschrijven.
- Een kolom verwijderen, erop groeperen of die aggregeren beantwoordt verschillende vragen.
- De groeperingsregel geldt ook voor gegroepeerde
HAVINGenORDER BY. - Door SQLite geaccepteerde niet-gegroepeerde, niet-geaggregeerde kolommen kunnen een onjuist rapport verhullen.
- Een gegroepeerde primaire sleutel bepaalt de andere kolommen van de bijbehorende rij.
2.3 Groepeer op meerdere kolommen en op berekende waarden
Sommige rapporten hebben een combinatie van categorieën nodig, of een categorie die voor elke rij wordt berekend. SQL kan op meerdere kolommen of op een expressie groeperen. De belangrijkste keuze blijft waar één uitvoerrij voor staat.
Groepeer op een combinatie
GROUP BY region, customer voegt rijen alleen samen wanneer beide waarden overeenkomen. Voer op de besteltabel uit:
SELECT region, customer, COUNT(*) AS orders, SUM(amount) AS total FROM orders GROUP BY region, customer ORDER BY region, customer;
De resultaten zijn East/Ana: twee bestellingen, 165; East/Dara: één, 95; North/Chen: twee, 350; West/Ben: twee, 140; en NULL/Eli: één, 30. De twee resultaten voor East tellen op tot het regionale totaal van 260.
Groeperen op customer, region vormt dezelfde combinaties. De kolomvolgorde in GROUP BY sorteert de uitvoer niet. De afzonderlijke ORDER BY hierboven kiest hoe die wordt weergegeven, met de standaardpositie voor NULL van de betreffende database.
Alleen combinaties die in de invoer voorkomen, verschijnen. Er is geen rij West/Ana met een aantal van nul. Groeperen vat bestaande rijen samen; het maakt niet elk mogelijk paar van categorielabels aan.
Voeg alleen detail toe wanneer dat nodig is
Een extra kolom splitst een groep alleen als de rijen verschillende waarden in die kolom bevatten. Groeperen op alleen klant geeft hier al vijf groepen. Met regio erbij zijn het er nog steeds vijf, omdat elke klant maar één regiowaarde heeft. Als je order_date aan een regionaal rapport toevoegt, ontstaan kleinere groepen voor de afzonderlijke datums en verandert de vraag die wordt beantwoord.
Groepeer datums op jaar en maand
Gebruik in SQLite strftime('%Y-%m', order_date) om een label zoals “2026-02” te maken:
SELECT strftime('%Y-%m', order_date) AS month, COUNT(*) AS orders, SUM(amount) AS total FROM orders GROUP BY strftime('%Y-%m', order_date) ORDER BY month;
Januari heeft twee bestellingen met een totaal van 200, februari heeft er drie met een totaal van 305 en maart heeft er drie met een totaal van 275. Vervang in PostgreSQL beide voorkomens van strftime('%Y-%m', order_date) door to_char(order_date, 'YYYY-MM') voor een DATE-kolom.
Groeperen op alleen het maandnummer voegt dezelfde maand uit verschillende jaren samen. Januari 2025 en januari 2026 zouden één groep worden. Door het jaar in de groeperingsexpressie te houden, blijven kalendermaanden gescheiden.
De expressie herhalen in GROUP BY maakt de groepering expliciet. SQLite, PostgreSQL en MySQL accepteren ook de uitvoeralias, zoals GROUP BY month; SQL Server accepteert daar geen SELECT-alias van hetzelfde niveau.
Maak categorieën met CASE
Een CASE-expressie kan elke bestelling vóór het groeperen een label geven:
SELECT CASE WHEN amount >= 100 THEN 'large' ELSE 'small' END AS size, COUNT(*) AS orders, SUM(amount) AS total FROM orders GROUP BY CASE WHEN amount >= 100 THEN 'large' ELSE 'small' END;
De categorie large bevat 120, 200 en 150: drie bestellingen met een totaal van 470. De categorie small bevat vijf bestellingen met een totaal van 310. De grenswaarde is inclusief, dus een bedrag van precies 100 hoort bij “large”. Dezelfde CASE-expressie staat in de weergave en de groepering, zodat beide dezelfde categoriedefinitie gebruiken.
Belangrijkste punten
- Meerdere groeperingskolommen geven combinaties aan die in de gegevens voorkomen.
- Een extra kolom splitst alleen groepen waarin die kolom varieert.
- Neem naast de maand ook het jaar op om kalendermaanden te onderscheiden.
- Gebruik dezelfde categorie-expressie in het geselecteerde label en de groepering.
GROUP BYmaakt geen ontbrekende combinaties met aantallen van nul aan.- De volgorde van groeperingskolommen bepaalt de uitvoervolgorde niet.
3Filter gegroepeerde resultaten met HAVING
Filteren kan de rijen veranderen die in een berekening worden gebruikt of bepalen welke voltooide samenvattingen in een rapport verschijnen. Die keuzes beantwoorden verschillende vragen. Je gebruikt HAVING om groepen te behouden op basis van aantal, totaal of gemiddelde en combineert dit met WHERE zonder de bedoelde betekenis te veranderen. De logische volgorde van een query volgen maakt het gemakkelijker om elke voorwaarde te plaatsen en het resultaat te voorspellen voordat je SQL uitvoert.
3.1 Behoud de groepen die aan een voorwaarde voldoen
HAVING toetst groepen nadat hun aggregaties zijn berekend. Gebruik het voor een vraag zoals “regio's met een totale omzet boven 200”. De voorwaarde beschrijft elk regionaal totaal, niet één afzonderlijke bestelling.
Eerst berekenen, dan groepen behouden
SELECT region, COUNT(*) AS orders, SUM(amount) AS total FROM orders GROUP BY region HAVING SUM(amount) > 200;
Vóór HAVING zijn de regionale totalen East 260, North 350, West 140 en NULL 30. De voorwaarde behoudt East met drie bestellingen en North met twee. Ze verwijdert de andere twee resultaatgroepen; ze verwijdert geen afzonderlijke bestellingen uit East of North.
Plaats HAVING in geschreven SQL na GROUP BY en vóór ORDER BY. Het sorteren wordt vervolgens toegepast op de groepen die aan de voorwaarde voldoen.
Filter op kengetallen die je niet weergeeft
SELECT region FROM orders GROUP BY region HAVING COUNT(*) >= 2; geeft East, North en West terug. De database kan de rijen van een groep tellen om te bepalen of die voldoet, zonder dat aantal weer te geven. HAVING en SELECT hoeven niet dezelfde lijst met aggregatiefuncties te hebben.
Je kunt groepsvoorwaarden combineren. HAVING COUNT(*) >= 2 AND AVG(amount) > 80 behoudt East en North. East heeft drie bestellingen en een gemiddelde van ongeveer 86,67; North heeft er twee en een gemiddelde van 175. West heeft genoeg bestellingen, maar het gemiddelde is slechts 70. Beide toetsen moeten slagen omdat ze met AND zijn verbonden; met OR zou één geslaagde toets volstaan.
Vind herhaalde waarden
Met groeperen en tellen vind je ook dubbele waarden:
SELECT customer, COUNT(*) AS orders FROM orders GROUP BY customer HAVING COUNT(*) > 1;
Ana, Ben en Chen hebben elk twee bestellingen en voldoen aan de voorwaarde. Dara en Eli hebben er één en voldoen niet. Om herhaalde e-mailwaarden in een klanttabel te vinden, groepeer je met hetzelfde patroon op email en behoud je aantallen boven één. Het aantal is het aantal records dat die waarde deelt.
Gebruik de expressie die de voorwaarde nodig heeft
Herhaal de aggregatiefunctie in HAVING: HAVING SUM(amount) > 200. PostgreSQL en standaard-SQL staan de uitvoeralias total niet toe in die voorwaarde op hetzelfde niveau, hoewel SQLite en MySQL dat wel doen. Een alias kun je veilig gebruiken in een latere ORDER BY total DESC.
Een weergegeven afgeronde waarde en de getoetste waarde kunnen verschillen. Het exacte gemiddelde van East is 260 gedeeld door drie. Als je ROUND(AVG(amount), 2) selecteert maar HAVING AVG(amount) > 86.67 schrijft, wordt East verwijderd: het niet-afgeronde gemiddelde ligt onder 86,67. North blijft over. De voorwaarde gebruikt precies de expressie die in HAVING staat. Alleen HAVING ROUND(AVG(amount), 2) ... zou de afgeronde waarde toetsen.
Filter de ene totale groep
HAVING kan ook werken zonder een expliciete GROUP BY. SELECT COUNT(*) FROM orders HAVING COUNT(*) > 5; behandelt alle acht bestellingen als één groep, voldoet aan de toets en geeft een rij met acht terug. Als je de voorwaarde vervangt door COUNT(*) > 10, krijg je geen rijen terug, geen rij met nul.
PostgreSQL ondersteunt dit patroon, net als SQLite vanaf versie 3.39.0. In een oudere SQLite-installatie heeft een query met HAVING een expliciete GROUP BY nodig.
Belangrijkste punten
HAVINGbehoudt of verwijdert voltooide groepen.- Een aggregatiefunctie in
HAVINGhoeft niet inSELECTte staan. - Combineer groepstoetsen met
AND,ORenNOT. - Herhaal aggregatie-expressies in
HAVINGvoor overdraagbare query's. - Een voorwaarde toetst haar eigen expressie, die niet afgerond hoeft te zijn.
3.2 Kies tussen WHERE en HAVING
Een voorwaarde hoort op de plaats waar datgene wat ze beschrijft bestaat. Afzonderlijke bestellingen bestaan vóór de groepering. Een regionaal totaal bestaat pas nadat de bestellingen zijn gegroepeerd en opgeteld.
Volg de logische volgorde
SQL wordt geschreven als SELECT, FROM, WHERE, GROUP BY, HAVING, ORDER BY, LIMIT. Om over het resultaat te redeneren, volg je deze logische volgorde:
FROMlevert de rijen.WHEREbehoudt rijen die aan de voorwaarde voldoen.GROUP BYvormt groepen en aggregatiefuncties berekenen hun kengetallen.HAVINGbehoudt groepen die aan de voorwaarde voldoen.SELECTlevert de uitvoerwaarden;DISTINCTverwijdert zo nodig dubbele uitvoerrijen.ORDER BYsorteert het resultaat enLIMITbehoudt het gevraagde aantal rijen.
De database kan de interne uitvoering anders indelen.
Plaats elke voorwaarde op het juiste niveau
| Vraag | Clausule |
|---|---|
Bestellingen met amount >= 60 | WHERE |
| Bestellingen in een gegeven datumbereik | WHERE |
Regio's met SUM(amount) > 200 | HAVING |
| Klanten met meer dan één bestelling | HAVING COUNT(*) > 1 |
WHERE SUM(amount) > 200 mislukt omdat het totaal tijdens het filteren van rijen nog niet bestaat. Over een rijvoorwaarde zoals region = 'East' kan vóór het groeperen worden beslist; die hoort in WHERE.
Doorloop beide filters
SELECT region, COUNT(*) AS orders, SUM(amount) AS total FROM orders WHERE amount >= 60 GROUP BY region HAVING SUM(amount) > 200;
Verwijder eerst de bestellingen van 45 en 30. East bevat nu 120 en 95, North bevat 200 en 150 en West bevat 80 en 60. Bereken vervolgens de totalen 215, 350 en 140. Behoud ten slotte totalen boven 200. De uitvoer is East met twee bestellingen en 215 en North met twee en 350. De NULL-regio heeft geen resterende rijen en vormt dus geen groep.
Verander de vraag niet bij het verplaatsen van een filter
“Bereken voor elke regio het gemiddelde van alleen bestellingen van 60 of meer” gebruikt WHERE amount >= 60. Het gemiddelde van East wordt 107,5 op basis van 120 en 95.
HAVING MIN(amount) >= 60 vraagt naar regio's waar elk bedrag dat niet NULL is aan de grenswaarde voldoet. East wordt verwijderd omdat het minimum 45 is; North en West blijven met hun oorspronkelijke bestellingen over. Het verplaatsen van de toets veranderde de betekenis van afzonderlijke bestellingen selecteren naar hele regio's accepteren of afwijzen.
Voor dit regionale rapport geeft region <> 'West' hetzelfde resultaat in WHERE of HAVING: East en North blijven over en ook de NULL-groep voldoet niet aan de vergelijking. WHERE geeft de rijbeperking direct aan en past die vóór het groeperen toe. Om ook ontbrekende regio's te behouden, heeft de voorwaarde een expliciete OR region IS NULL nodig.
SELECT-aliassen zijn in PostgreSQL niet beschikbaar in de eerdere clausules WHERE en HAVING. SQLite staat meer gebruik van aliassen toe, maar door de invoerkolom of expressie uit te schrijven blijft duidelijk in welke fase die wordt gebruikt.
Belangrijkste punten
WHEREverandert de invoer van aggregatiefuncties;HAVINGfiltert aggregatieresultaten.- Plaats voorwaarden over het aantal, totaal of gemiddelde van een groep in
HAVING. - Volg bij het voorspellen van een resultaat het filteren van rijen vóór het groeperen.
- Een toets op het minimum van een groep kan een hele groep verwijderen.
4Bereken exacte en correct afgeronde resultaten
Een query kan de juiste rijen kiezen en toch het gedeelte achter de komma van het antwoord verliezen. Getaltypen bepalen de deling en de resultaten van aggregatiefuncties, terwijl afronding bepaalt hoeveel precisie je toont. Je behoudt decimalen tijdens berekeningen, kiest een passende behandeling voor een lege noemer en rondt alleen het uiteindelijke kengetal af. Dezelfde korte expressie kan zich anders gedragen in verschillende databases, dus elk relevant verschil wordt aangegeven.
4.1 Voorkom gehele deling bij gemiddelden en percentages
Als je twee gehele getallen deelt, kan het gedeelte achter de komma al verdwijnen voordat je het antwoord weergeeft. Dat is van belang wanneer je een gemiddelde of percentage berekent uit totalen en aantallen.
Zorg vóór de deling voor een decimale operand
In SQLite en PostgreSQL geeft 7 / 2 3 terug. Bij invoer van gehele getallen geeft SUM(quantity) / COUNT(*) op de besteltabel 2 terug: bij 19 artikelen gedeeld door acht bestellingen gaat het gedeelte achter de komma verloren. De SUM van een INTEGER-kolom geeft in PostgreSQL BIGINT terug, waarbij hier nog steeds gehele deling wordt gebruikt.
Schrijf 1.0 * SUM(quantity) / COUNT(*) om in beide databases 2,375 te krijgen. Vermenigvuldigen met 1,0 levert vóór de deling een decimale operand op. SUM(quantity) / COUNT(*) * 1.0 geeft 2,0 omdat de deling het gedeelte achter de komma al heeft verwijderd. Bewerkingen met dezelfde prioriteit worden van links naar rechts uitgevoerd.
Voor deze tabel geeft AVG(quantity) direct 2,375 in SQLite en PostgreSQL. De handmatige formule is van belang wanneer je een andere noemer of een percentage nodig hebt.
Bereken een percentage
Drie van de acht bestellingen hebben een bedrag van minstens 100. Het aantal van die bestellingen gedeeld door het aantal van alle bestellingen meet hun aandeel. Vermenigvuldig met 100,0:
SELECT 100.0 * COUNT(CASE WHEN amount >= 100 THEN 1 END) / COUNT(*) AS pct_large FROM orders;
Het resultaat is 37,5. Als je in plaats daarvan het gehele getal 100 gebruikt, krijg je 37 in SQLite en bij deling van gehele aantallen in PostgreSQL. Later afronden zou alleen veranderen hoe 37 wordt weergegeven.
Een query over de hele tabel kan geen overeenkomende rijen hebben. NULLIF(COUNT(*), 0) geeft NULL terug wanneer het aantal nul is, zodat 100.0 * COUNT(discount) / NULLIF(COUNT(*), 0) NULL teruggeeft bij lege invoer. Een noemer van nul zonder beveiliging geeft een fout in PostgreSQL; SQLite geeft NULL terug. Een aandeel van NULL kan duidelijk aangeven dat er “geen bestellingen zijn om te meten”.
Controleer de database en het invoertype
| Database | Gedrag om op te letten |
|---|---|
| SQLite | Gehele deling kapt decimalen af; AVG geeft een drijvendekommagetal terug. |
| PostgreSQL | Gehele deling kapt decimalen af; AVG van gehele invoer of NUMERIC-invoer geeft NUMERIC terug. |
| SQL Server | Gehele deling kapt decimalen af; AVG van gehele invoer geeft een geheel getal terug. |
| MySQL en Oracle | / behoudt het gedeelte achter de komma bij gehele operanden. |
Gebruik in SQL Server AVG(quantity * 1.0) of converteer de invoer naar DECIMAL voordat je het gemiddelde berekent. In PostgreSQL geeft SUM van een BIGINT-kolom NUMERIC terug, zodat de deling zich anders kan gedragen dan bij SUM van een INTEGER-kolom. MySQL geeft DECIMAL terug voor sommen van gehele invoer.
Een typeconversie kan ook de benodigde decimale operand maken: gebruik CAST(SUM(quantity) AS REAL) in SQLite of CAST(SUM(quantity) AS NUMERIC) in PostgreSQL. De conversie naar NUMERIC in SQLite kan een geheel getal behouden, zodat die conversie alleen geen decimale deling garandeert.
Maak onderscheid tussen exacte decimalen en benaderingen
Drijvendekommatypen slaan binaire benaderingen op. NUMERIC en DECIMAL in PostgreSQL ondersteunen exacte decimale waarden; optellingen met drijvendekommagetallen kunnen kleine afwijkingen zoals 0,30000000000000004 weergeven. De NUMERIC-typeaffiniteit van SQLite biedt geen exacte decimale opslag. Voor exacte geldtotalen sla je daar hele centen op, tel je die op en deel je voor de weergave door 100,0.
Belangrijkste punten
- Maak een decimale operand voordat je gehele totalen of aantallen deelt.
- Vermenigvuldigen na gehele deling kan verloren cijfers niet herstellen.
- Gebruik
NULLIFom een noemer van nul af te handelen. - Resultaattypen van aggregatiefuncties hangen af van zowel de database-engine als het invoertype.
- De
NUMERIC-typeaffiniteit van SQLite biedt geen exacte decimale opslag. - SQL Server heeft decimale invoer nodig voor een gemiddelde van gehele getallen met decimalen.
4.2 Rond geaggregeerde resultaten af
Afronden bepaalt hoeveel cijfers een resultaat toont. Bewaar de volledige berekening tot de laatste stap, zodat keuzes voor de weergave het kengetal dat je berekent niet veranderen.
Rond een aggregatieresultaat af
ROUND(x, n) rondt af op n cijfers achter de komma. ROUND(x) rondt af op een geheel getal. Zo is ROUND(3.14159, 2) gelijk aan 3,14.
SELECT region, ROUND(AVG(amount), 2) AS avg_amount FROM orders GROUP BY region; geeft East 86,67, North 175, West 70 en NULL-regio 30. SQLite kan 175,0 tonen, terwijl het NUMERIC-resultaat van PostgreSQL 175,00 toont. Deze geven hetzelfde getal weer. Een getal afronden en een tekstlabel met een vaste breedte opmaken zijn verschillende taken.
Rond af na optellen of middelen
Bij drie vergoedingen van 0,44 tel je eerst op tot 1,32 en rond je daarna af op één decimaal voor 1,3. ROUND(SUM(fee), 1) volgt die volgorde. SUM(ROUND(fee, 1)) rondt elke vergoeding af op 0,4 en telt ze daarna op, wat 1,2 oplevert. Door vroeg af te ronden is het totaal veranderd.
Evenzo geeft ROUND(100 * 1 / 3, 1) 33,0 in SQLite en PostgreSQL, omdat gehele deling al 33 heeft opgeleverd. ROUND(100.0 * 1 / 3, 1) behoudt het gedeelte achter de komma en geeft 33,3. Kies het berekeningstype vóór het afronden.
Afgeronde aandelen tellen mogelijk niet op tot 100%. Drie gelijke aandelen kunnen elk als 33,3% worden weergegeven, samen 99,9%. De onderliggende aandelen vormen nog steeds het geheel. Als je één willekeurig aandeel opnieuw berekent om het weergegeven totaal te laten kloppen, verandert de betekenis van dat weergegeven getal.
Gebruik een ondersteund invoertype
PostgreSQL ondersteunt ROUND(value, n) met twee argumenten voor NUMERIC. Als temp van het type DOUBLE PRECISION is, schrijf je ROUND(CAST(AVG(temp) AS NUMERIC), 2). Het gemiddelde van 20,5; 21,25 en 19,0 is 20,25 en door de typeconversie kun je afronden met twee argumenten. Bij een amount met gehele getallen is het gemiddelde in PostgreSQL al NUMERIC, dus is geen typeconversie nodig.
Voor exacte NUMERIC-waarden worden waarden halverwege twee afrondingsuitkomsten van nul af afgerond: 2,5 wordt 3 en -2,5 wordt -3. SQLite geeft voor deze voorbeelden ook 3,0 en -3,0. Afronding van drijvendekommagetallen in PostgreSQL hangt af van het platform; afronding naar het dichtstbijzijnde even getal komt vaak voor. Een binaire benadering kan een decimaal getal ook net onder een bedoeld midden plaatsen. Gebruik een specifieke drijvendekommawaarde halverwege twee uitkomsten niet als algemene regel voor exacte decimale rekenkunde.
Let op twee andere verschillen tussen dialecten
PostgreSQL, MySQL, SQL Server en Oracle gebruiken een negatief aantal decimalen om links van de komma af te ronden. ROUND(1234.5, -2) geeft 1200. SQLite behandelt een negatief tweede argument als nul en geeft 1235,0. Gebruik ROUND(x / 100.0) * 100 om in SQLite op honderdtallen af te ronden.
Converteren naar een geheel getal verschilt ook per database: SQLite kapt het gedeelte achter de komma af, zodat 2,9 verandert in 2; PostgreSQL rondt het af naar 3. Gebruik ROUND wanneer afronden het doel is. TRUNC(x, n) in PostgreSQL kapt daarentegen cijfers af: TRUNC(2.97, 1) is 2,9, terwijl afronden op één decimaal 3,0 geeft.
Belangrijkste punten
- Rond het aggregatieresultaat af nadat de berekening is voltooid.
- Afronden kan eerdere gehele deling niet herstellen.
- Afgeronde percentages kunnen optellen tot 99,9% of 100,1%.
- Converteer een drijvendekommagemiddelde in PostgreSQL naar
NUMERICvoorROUNDmet twee argumenten. - Negatieve afrondingsposities en conversies naar gehele getallen verschillen per database.
5Beantwoord bedrijfsvragen met aggregatiequery's
Bedrijfsrapporten hebben vaak meerdere kengetallen voor dezelfde populatie nodig: alle bestellingen, grote bestellingen en het aandeel dat groot is. Voorwaardelijke aggregatie houdt die kengetallen naast elkaar. Daarna stel je op basis van de vraag een volledig rapport samen, controleer je totalen en ontbrekende categorieën en gebruik je een tweede aggregatiestap wanneer de vraag over klanten of andere groepen gaat in plaats van over afzonderlijke bestellingen.
5.1 Tel en sommeer onder voorwaarden met CASE
Met voorwaardelijke aggregatie kunnen verschillende kengetallen verschillende bijdragen gebruiken, terwijl dezelfde totale verzameling rijen behouden blijft. Een CASE-expressie bepaalt wat elke rij aan een telling of som bijdraagt.
Tel rijen die aan de voorwaarde voldoen
COUNT(CASE WHEN amount >= 100 THEN 1 END) telt bestellingen van minstens 100. De expressie geeft 1 terug bij een overeenkomst en NULL voor andere rijen omdat er geen ELSE is. COUNT slaat die NULL-waarden over, zodat drie overeenkomsten in de besteltabel overblijven.
SUM(CASE WHEN amount >= 100 THEN 1 ELSE 0 END) telt overeenkomsten door enen en nullen op te tellen. Bij bestaande invoerrijen geeft dit dezelfde telling. COUNT(CASE WHEN amount >= 100 THEN 1 ELSE 0 END) doet dat niet: zowel 1 als 0 is geen NULL, dus telt de functie alle acht bestellingen.
Tel bedragen op die aan de voorwaarde voldoen
Geef voor een voorwaardelijk totaal het bedrag zelf terug:
SELECT region, COUNT(*) AS orders, COUNT(CASE WHEN amount >= 100 THEN 1 END) AS large_orders, SUM(CASE WHEN amount >= 100 THEN amount ELSE 0 END) AS large_total FROM orders GROUP BY region;
East heeft drie bestellingen, één grote bestelling en een totaal voor grote bestellingen van 120. North heeft twee bestellingen, beide groot, met een totaal van 350. West heeft twee bestellingen, geen grote bestellingen en een totaal voor grote bestellingen van nul. De NULL-regiogroep heeft één bestelling en nullen voor beide kengetallen voor grote bestellingen.
De uitvoer behoudt West omdat de invoerrijen nog bestaan. Als je WHERE amount >= 100 zou toevoegen, zouden de rijen van West vóór het groeperen worden verwijderd en zou West verdwijnen. Dat filter zou ook zorgen dat COUNT(*) alleen grote bestellingen telt, waardoor de vergelijking met alle bestellingen verloren gaat.
Gebruik de juiste noemer
Bereken binnen elke regio het percentage grote bestellingen met ROUND(100.0 * COUNT(CASE WHEN amount >= 100 THEN 1 END) / COUNT(*), 1) AS pct_large. East geeft 33,3, North 100,0, West 0,0 en de NULL-groep 0,0. Elke noemer is het aantal bestellingen van die groep, niet het aantal van acht voor de hele tabel.
Beveilig voor een ongegroepeerd rapport dat geen rijen kan bevatten de noemer met NULLIF(COUNT(*), 0). Een telling bij lege invoer is nul, maar een percentage van een lege populatie heeft geen noemer.
Maak meerdere categoriekolommen
Eén resultaat kan één telling per regio tonen:
SELECT COUNT(CASE WHEN region = 'East' THEN 1 END) AS east, COUNT(CASE WHEN region = 'West' THEN 1 END) AS west, COUNT(CASE WHEN region = 'North' THEN 1 END) AS north FROM orders;
De aantallen zijn drie, twee en twee. De bestelling van Eli voldoet aan geen van deze toetsen voor een benoemde regio. Voeg COUNT(CASE WHEN region IS NULL THEN 1 END) toe om de ene bestelling met ontbrekende regio te tellen. Een NULL-regio vergelijken met een naam levert geen ware voorwaarde op.
Herken alternatieve syntaxis
PostgreSQL en SQLite vanaf versie 3.30.0 ondersteunen COUNT(*) FILTER (WHERE amount >= 100). Het filter geldt voor die aggregatiefunctie, zodat een naastgelegen ongefilterde COUNT(*) nog steeds alle bestellingen telt. MySQL en SQL Server ondersteunen deze FILTER-syntaxis bij aggregatiefuncties niet; de CASE-vorm werkt wel op beide.
SQLite en MySQL staan ook SUM(amount >= 100) toe omdat vergelijkingen numerieke waarheidswaarden opleveren. PostgreSQL weigert SUM van booleaanse waarden. Gebruik de CASE-vorm wanneer een query in deze databases moet werken.
Belangrijkste punten
- Plaats voorwaarden binnen aggregatiefuncties om kengetallen voor verschillende deelverzamelingen bij elkaar te houden.
COUNT(CASE ... THEN 1 END)slaat rijen over die niet voldoen.ELSE 0werkt voor een voorwaardelijke som, maar zorgt dat een voorwaardelijke telling ook rijen telt die niet voldoen.- Een percentage binnen een groep gebruikt de populatie van die groep als noemer.
- Een
FILTERbij een aggregatiefunctie verandert alleen de invoer van die functie. - Gebruik
IS NULLvoor een afzonderlijke telling van ontbrekende categorieën.
5.2 Stel op basis van een vraag een aggregatiequery op en controleer deze
Een aggregatiequery begint met een vraag over een populatie op een bepaald detailniveau. Zet die keuzes om voordat je SQL schrijft en controleer daarna of de uitvoer nog steeds de oorspronkelijke vraag beantwoordt.
Stel het rapport in volgorde op
Vraag: “Hoeveel bestellingen zijn geplaatst en wat was het gemiddelde bedrag, op twee decimalen, voor elke maand van 2026 met minstens drie bestellingen?”
- De kengetallen zijn
COUNT(*)enAVG(amount). - Het detailniveau, oftewel de betekenis van één resultaatrij, is één kalendermaand.
- De rijvoorwaarde behoudt datums in 2026.
- De groepsvoorwaarde vereist minstens drie bestellingen.
- De uitvoer moet op maand worden gesorteerd, met het gemiddelde afgerond voor de weergave.
In SQLite:
SELECT strftime('%Y-%m', order_date) AS month, COUNT(*) AS orders, ROUND(AVG(amount), 2) AS avg_amount FROM orders WHERE order_date >= '2026-01-01' AND order_date < '2027-01-01' GROUP BY strftime('%Y-%m', order_date) HAVING COUNT(*) >= 3 ORDER BY month;
Voor datumwaarden in PostgreSQL vervang je de maandexpressie op beide plaatsen door to_char(order_date, 'YYYY-MM'). Het datumbereik omvat het begin van 2026 en sluit het begin van 2027 uit.
Januari heeft twee bestellingen en voldoet niet aan de groepsvoorwaarde. Februari heeft drie bestellingen met een totaal van 305 en een gemiddelde van 101,67. Maart heeft er drie met een totaal van 275 en een gemiddelde van 91,67. De overgebleven groepen vertegenwoordigen zes bestellingen, geen acht, omdat HAVING januari heeft verwijderd.
Controleer voordat je groepen wegfiltert
Voer het rapport eerst zonder HAVING uit. De aantallen over alle groepen moeten optellen tot het aantal rijen onder hetzelfde WHERE-filter en de totalen moeten optellen tot het ongegroepeerde totaal. Hier geven die controles acht en 780. Vergelijk de totalen van behouden groepen niet met de hele invoer nadat enkele groepen zijn uitgesloten.
Zoek naar een NULL-groep, bekijk de volgorde van de resultaten en bereken een groep opnieuw door de oorspronkelijke tabel te filteren. Voor East moet WHERE region = 'East' drie bestellingen met een totaal van 260 geven. Een verschil kan wijzen op een extra groeperingskolom, een verkeerd geplaatst rijfilter of een expressie die NULL is geworden.
Maak onderscheid tussen een gemiddelde bestelling en een gemiddelde klant
AVG(amount) is 97,5 per bestelling. De gemiddelde besteding per klant vraagt om een andere eenheid: de vijf klanttotalen zijn 165, 140, 350, 95 en 30. Hun gemiddelde is 156.
Bereken dat in twee stappen:
SELECT AVG(total) AS avg_customer_total FROM (SELECT customer, SUM(amount) AS total FROM orders GROUP BY customer) AS per_customer;
De binnenste query maakt één rij per klant. De buitenste query berekent het gemiddelde van die rijen, zodat elke klant één bijdrage levert. Omdat alle klanten een naam hebben, geeft 1.0 * SUM(amount) / COUNT(DISTINCT customer) dezelfde 156. Door ongelijke aantallen bestellingen is het middelen van bestelbedragen een andere berekening.
Vat de groepen zelf samen
Om klanten met meer dan één bestelling te tellen, geef je ze eerst weer en tel je daarna hun rijen:
SELECT COUNT(*) FROM (SELECT customer FROM orders GROUP BY customer HAVING COUNT(*) > 1) AS repeat_customers;
Het antwoord is drie. Aggregatiefuncties rechtstreeks nesten, zoals in MAX(AVG(amount)) op één queryniveau, mislukt in SQLite en PostgreSQL. Om de regio met het hoogste gemiddelde te vinden, sorteer je de gegroepeerde gemiddelden: ORDER BY AVG(amount) DESC LIMIT 1 geeft North met 175 terug. Oracle ondersteunt ook geneste groepsfuncties, maar een afzonderlijk queryniveau maakt de twee berekeningen expliciet. Controleer op gelijke waarden wanneer een rapport om een hoogste resultaat vraagt.
Belangrijkste punten
- Kies kengetallen, detailniveau, rijvoorwaarden en groepsvoorwaarden op basis van de vraag.
- Controleer groepsaantallen en -totalen voordat je groepen met
HAVINGverwijdert. - Een gemiddelde per klant heeft klanttotalen als invoer nodig.
- Gebruik een binnenste gegroepeerde query en een buitenste aggregatiefunctie om groepen samen te vatten.
SQL GROUP BY: voorbeelden
1Zet bestelrijen om in betrouwbare samenvattende getallen
13 stappen
- 1IntroductieLees de vraag voor het rapport
Een manager wil een besteltotaal, een aantal klanten en een gemiddelde korting. Elk klinkt als een eenvoudig getal, maar elk gebruikt de invoer anders. Elk is een aggregatie, die veel rijen tot één waarde omzet, en de verkeerde keuze geeft een misleidend getal. We maken die kengetallen op basis van de acht bestellingen: eerst combineren we bedragen, dan kiezen we wat we tellen en daarna bepalen we hoe NULL het gemiddelde verandert. Blijf vragen wat één invoerrij aan het resultaat bijdraagt.
- 2UitlegCombineer de bedragen
Een aggregatie combineert waarden uit meerdere rijen tot één samenvatting.
SUM(amount)telt de bedragen op,AVG(amount)bepaalt hun gemiddelde enMIN(amount)enMAX(amount)vinden de uiterste waarden. ZonderGROUP BYvormen alle bestellingen die aan de voorwaarden voldoen één groep. Je kunt meerdere aggregatiefuncties samen selecteren omdat ze elk dezelfde groep invoerrijen beschrijven. - 3VoorbeeldBereken één volledige samenvatting
De bestelbedragen zijn 120, 80, 45, 200, 60, 95, 150 en 30. Samen zijn ze 780. Dat totaal gedeeld door acht geeft een gemiddelde van 97,5; het kleinste bedrag is 30 en het grootste is 200.
SELECT SUM(amount) AS total, AVG(amount) AS mean_amount, MIN(amount) AS low, MAX(amount) AS high FROM orders;De uitvoer is één rij met vier kengetallen met een label.
- 4VoorbeeldKies de invoer vóór het optellen
Vraag nu alleen naar East.
WHERE region = 'East'behoudt de bedragen 120, 45 en 95 voordat de aggregatiefunctie wordt toegepast.SELECT SUM(amount) AS total FROM orders WHERE region = 'East';De uitvoer is 260. De andere regio's dragen niets bij omdat hun bestellingen niet aan de rijvoorwaarde voldeden. Een filter op invoerrijen verandert het totaal zelf, niet alleen het weergegeven label.
- 5UitdagingHoud een aantal bij de bijbehorende prijs
Een verkooptabel heeft twee rijen: aantal 4 tegen een prijs per stuk van 6 en aantal 2 tegen een prijs per stuk van 9. Wat geeft
SUM(quantity * unit_price)terug en waarom is het vermenigvuldigen van de twee sommen anders?---reveal---
De omzetten per rij zijn 24 en 18, dus de som is 42. De sommen vermenigvuldigen geeft zes keer 15, oftewel 90, omdat elk aantal dan niet meer wordt gekoppeld aan de prijs uit de eigen rij.
- 6UitlegTel records of klanten
De bestellingen vermelden Ana, Ben, Ana, Chen, Ben, Dara, Chen en Eli.
COUNT(customer)telt acht vastgelegde namen, inclusief herhaalde vermeldingen.COUNT(DISTINCT customer)telt vijf verschillende namen.De formulering bepaalt welke telling past: voor een aantal bestellingen heb je rijen nodig, voor een aantal klanten unieke klanten. Gelijke namen op afzonderlijke bestellingen zijn verwachte herhalingen, geen extra klanten.
- 7VoorbeeldTel de ontbrekende categorie
De regiokolom heeft acht rijen maar slechts zeven vastgelegde waarden.
COUNT(*)is acht,COUNT(region)is zeven enCOUNT(DISTINCT region)is drie.Als je de telling van vastgelegde waarden aftrekt van het aantal rijen, krijg je één ontbrekende regio. Een lijst met unieke regio's zou ook een NULL-rij bevatten; de telling van unieke waarden negeert die NULL in plaats van die als een vierde benoemde regio te behandelen.
- 8UitdagingKies de juiste telling
Een kolom voor kortingsbonnen bevat NULL, 0, 8, 8 en 0. Welke waarden geven
COUNT(*),COUNT(coupon)enCOUNT(DISTINCT coupon)terug, in die volgorde?---reveal---
Ze geven vijf, vier en twee terug. Er zijn vijf rijen, vier vastgelegde waarden en twee verschillende vastgelegde waarden, 0 en 8. Vastgelegde nulwaarden tellen mee; NULL komt in geen van beide kolomtellingen terecht.
- 9UitlegLaat een onbekende score weg
Bekijk de scores 80, NULL, 70 en 90. De vastgelegde scores zijn samen 240.
AVG(score)deelt door de drie vastgelegde scores en geeft 80 terug.De functie deelt niet door alle vier de rijen: een ontbrekende score is geen bekende nul. Als de ontbrekende waarde een gemist examen voorstelt dat als nul moet tellen, verandert de bedoelde berekening in
AVG(COALESCE(score, 0)), wat 60 geeft. - 10VoorbeeldPlaats de standaardwaarde in de juiste fase
Bij vier bestellingen ontbreekt de korting. In
SUM(amount - discount)wordt elk van die rijexpressies NULL, zodat alleen de andere vier bijdragen. Hun nettobedragen tellen op tot 345.Als ontbrekend betekent dat er geen korting is, gebruik je
SUM(amount - COALESCE(discount, 0)). Alle acht bestellingen dragen dan bij en het totaal is 750.COALESCErond de voltooide som kan weggelaten bijdragen van rijen niet terugbrengen. - 11UitdagingVerwerk een groep zonder bekende waarden
Een query behoudt drie rijen waarvan de bedragen allemaal NULL zijn. Wat geven
COUNT(*),COUNT(amount)enSUM(amount)terug?---reveal---
Ze geven drie, nul en NULL terug. Er bestaan rijen, maar er zijn geen vastgelegde bedragen om te tellen of op te tellen. Lege invoer zou ook een NULL-som geven, maar het aantal rijen zou nul zijn. Gebruik
COALESCE(SUM(amount), 0)alleen wanneer het rapport dat ontbrekende totaal als nul moet tonen. - 12UitdagingControleer een berekening en de bijbehorende populatie
Vier dienstrecords hebben kosten van 20, 30, 40 en 50, met tegoeden van 2, NULL, 0 en NULL. Een ontbrekend tegoed betekent geen tegoed. Welk totaal aan nettokosten en welk aantal vastgelegde tegoeden moet het rapport tonen?
---reveal---
Gebruik
SUM(charge - COALESCE(credit, 0))voor een nettototaal van 138 enCOUNT(credit)voor twee vastgelegde tegoeden. Het tegoed van nul telt als vastgelegd; door NULL binnen de som te vervangen, blijven alle vier de kostenbedragen behouden. - 13SamenvattingHoud het kengetal gekoppeld aan de invoer
Kies de aggregatiefunctie op basis van de vraag en volg daarna de waarden die erin gaan. Tellingen onderscheiden rijen, vastgelegde gegevens en verschillende gegevens. Controleer bij gemiddelden en berekeningen per rij wat NULL weglaat en of een vervanging een werkelijke betekenis heeft. Als een antwoord verrassend lijkt, bekijk dan de overgebleven rijen en hun bijdragen voordat je de SQL verandert.
2Maak een rapport op het juiste detailniveau
14 stappen
Sla deze les op om elke Walkthrough stap voor stap te volgen.
- 1IntroductieBepaal waar een resultaatrij voor staat
- 2UitlegVerzamel rijen per regio
- 3VoorbeeldHoud de NULL-groep zichtbaar
- 4TipSorteer voordat je de hoogste rijen behoudt
- 5UitdagingVoorspel hoeveel groepen overblijven
- 6UitlegLeg uit waarom een naam dubbelzinnig is
- 7VoorbeeldPas het rapport aan de vraag aan
- 8TipHerken een resultaat dat door soepel gedrag ontstaat
- 9UitdagingKies een betekenisvolle oplossing
- 10VoorbeeldSplits een groep op een tweede waarde
- 11UitlegMaak een label voor een kalendermaand
- 12UitdagingVind de groeperingsexpressie
- 13UitdagingControleer het detailniveau en de labels van het rapport
- 14SamenvattingLees elke rij als één groep
3Plaats filters vóór of na aggregatie
10 stappen
Sla deze les op om elke Walkthrough stap voor stap te volgen.
- 1IntroductieMaak onderscheid tussen populatie en selectie
- 2UitlegToets de voltooide groep
- 3VoorbeeldGebruik een telling zonder die weer te geven
- 4UitdagingControleer de werkelijke waarde die wordt vergeleken
- 5UitlegVolg de logische fasen van het resultaat
- 6VoorbeeldVerwijder eerst kleine bestellingen
- 7VoorbeeldVerwijder daarna kleine groepstotalen
- 8UitdagingOnderzoek een veranderde vraag
- 9UitdagingCombineer rij- en groepsbeperkingen
- 10SamenvattingLaat de voorwaarde de fase bepalen
4Behoud decimalen en rond het eindresultaat af
11 stappen
Sla deze les op om elke Walkthrough stap voor stap te volgen.
- 1IntroductieHoud berekening en weergave gescheiden
- 2VoorbeeldZoek waar het gedeelte achter de komma verdwijnt
- 3UitlegVoeg de decimale operand vroeg toe
- 4TipBeveilig een lege noemer
- 5UitdagingHerstel een percentage-expressie
- 6UitlegRond het berekende gemiddelde af
- 7VoorbeeldZie hoe vroeg afronden een totaal verandert
- 8UitdagingControleer een verschil tussen dialecten
- 9VerbandKies het type voor exacte bedragen
- 10UitdagingControleer het type vóór het afronden
- 11SamenvattingVolg het getal door elke fase
5Stel een bedrijfssamenvatting op en controleer deze
13 stappen
Sla deze les op om elke Walkthrough stap voor stap te volgen.
- 1IntroductieHoud alle bestellingen en geselecteerde bestellingen bij elkaar
- 2UitlegLaat rijen die niet voldoen NULL bijdragen
- 3VoorbeeldHoud de volledige groep beschikbaar
- 4VoorbeeldTel het bedrag of één op
- 5UitdagingBehoud de noemer voor een deelverzameling
- 6UitlegVertaal de zakelijke formulering
- 7VoorbeeldMaak het maandresultaat
- 8TipControleer voordat je groepen verbergt
- 9UitlegVerander de invoereenheid voor een gemiddelde
- 10VoorbeeldLees de twee queryniveaus
- 11UitdagingKies de juiste eenheid voor het gemiddelde
- 12UitdagingTel alleen klantgroepen die voldoen
- 13SamenvattingControleer de populatie en het detailniveau
SQL GROUP BY: oefenvragen
Set 1: Lees tellingen, groepen en berekeningen10 Oefenvragen
Vraag 1 van 10
HAVING SUM(amount) > 200?Toon antwoordVerberg antwoord
>= 200. HAVING past deze vergelijking toe op elk voltooid teamtotaal en behoudt of verwijdert dus elk volledig teamresultaat.Vraag 2 van 10
SUM(distance) terug?Toon antwoordVerberg antwoord
SUM telt de drie afstanden op en geeft 71. De grootste afstand, 35, zou het resultaat van MAX(distance) zijn, terwijl een gemiddelde de gezamenlijke afstand door drie zou delen; geen van beide beantwoordt de vraag naar een totaal.Vraag 3 van 10
COUNT(CASE WHEN status = 'closed' THEN 1 ELSE 0 END) terug?Toon antwoordVerberg antwoord
Vraag 4 van 10
AVG(delay) terug?Toon antwoordVerberg antwoord
AVG deelt door hun aantal van drie, wat acht minuten geeft. Delen door alle vier de rijen zou zes minuten geven en de onbekende vertraging feitelijk door nul vervangen, hoewel zo'n meting niet is vastgelegd.Vraag 5 van 10
SELECT department, COUNT(*) FROM shifts GROUP BY department terug?Toon antwoordVerberg antwoord
Vraag 6 van 10
FROM parts GROUP BY category?Toon antwoordVerberg antwoord
COUNT(DISTINCT supplier) zet alle vastgelegde leverancierswaarden in een categorie om in één aantal verschillende leveranciers. Een gewone leverancierswaarde is dubbelzinnig omdat de categorie meerdere leveranciers kan hebben. COUNT(supplier) zou records met een leverancier tellen, inclusief herhaalde vermeldingen.Vraag 7 van 10
paid_on met records van 2024 tot en met 2026. Welke groeperingsexpressie houdt elke kalendermaand gescheiden?Toon antwoordVerberg antwoord
Vraag 8 van 10
ORDER BY supplier. Categorieën hebben meerdere leveranciers. Hoe kan de query de categorieën met de hoogste kosten eerst tonen zonder het detailniveau te veranderen?Toon antwoordVerberg antwoord
Vraag 9 van 10
SUM(quantity) / COUNT(*) * 1.0 terug?Toon antwoordVerberg antwoord
1.0 * SUM(quantity) / COUNT(*).Vraag 10 van 10
ROUND(SUM(fee), 1) maar behoudt de totale groep alleen met HAVING SUM(fee) >= 0.8. Welk resultaat geeft de query terug?Toon antwoordVerberg antwoord
Set 2: Kies de populatie en het detailniveau van het rapport10 Oefenvragen
Sla deze les op om elk antwoord te zien en elke set te oefenen.
Vraag 1 van 10
COUNT(priority) terug?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 2 van 10
Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 3 van 10
MIN(delivery_date) en MAX(delivery_date) in die volgorde terug?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 4 van 10
SELECT COUNT(*) FROM (SELECT DISTINCT city, agent FROM visits) AS pairs terug?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 5 van 10
SUM(cost - credit) en de bedoelde totale nettokosten, in die volgorde?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 6 van 10
ORDER BY total DESC, customer ASC LIMIT 2, als de namen alfabetisch worden gesorteerd?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 7 van 10
ROUND(SUM(fee), 1) en SUM(ROUND(fee, 1)) in die volgorde op, als je kleine weergaveafwijkingen door drijvendekommagetallen negeert?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 8 van 10
Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 9 van 10
SELECT training FROM roster GROUP BY training HAVING COUNT(*) >= 3 terug?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 10 van 10
WHERE amount >= 60 GROUP BY team HAVING AVG(amount) > 80?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Set 3: Combineer ontbrekende waarden, typen en groepen10 Oefenvragen
Sla deze les op om elk antwoord te zien en elke set te oefenen.
Vraag 1 van 10
SELECT 17 / 5 terug in SQLite?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 2 van 10
Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 3 van 10
Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 4 van 10
Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 5 van 10
SELECT SUM(quantity * price) FROM stock WHERE department = 'A' terug?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 6 van 10
COUNT(DISTINCT region) terug?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 7 van 10
jobs voldoen aan state = 'queued'. Wat geeft SELECT team, COALESCE(SUM(hours), 0) FROM jobs WHERE state = 'queued' GROUP BY team terug?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 8 van 10
WHERE area IS NOT NULL GROUP BY area de groepsaantallen?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 9 van 10
Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 10 van 10
CASE WHEN amount >= 100 THEN 'large' ELSE 'small' END. Hoeveel groepen ontstaan?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Set 4: Onderzoek en voltooi complete rapporten10 Oefenvragen
Sla deze les op om elk antwoord te zien en elke set te oefenen.
Vraag 1 van 10
Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 2 van 10
Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 3 van 10
WHERE amount >= 30 met alle rijen groeperen en HAVING MIN(amount) >= 30 gebruiken. Welke gemiddelden verschijnen?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 4 van 10
Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 5 van 10
temperature van het type DOUBLE PRECISION. Hoe rond je het gemiddelde af op twee decimalen?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 6 van 10
COUNT(*) FILTER (WHERE paid = 1) naast COUNT(*) in een gegroepeerde query zonder WHERE-clausule. Wat beperkt het filter?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 7 van 10
COUNT(*), COUNT(value) en MAX(value), in die volgorde?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 8 van 10
Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 9 van 10
WHERE zone <> 'West'. Welke zonegroepen kunnen overblijven?Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Vraag 10 van 10
Toon antwoordVerberg antwoord
Sla deze les op om dit antwoord te zien.
Kom je niet uit je eigen opgave? Huiswerkhulp
Kernbegrippen
A
Aansluitcontrole
HAVING uit, zodat uitgesloten groepen geen verschil tussen het rapport en het invoertotaal veroorzaken.Aanvullende sorteerkolom
ORDER BY total DESC, customer geeft gelijke klanttotalen een stabiele volgorde voordat een beperking wordt toegepast.Afgeleide tabel
FROM wordt gebruikt, zodat een tweede query de rijen van de eerste query kan samenvatten.Afkappen
TRUNC en SQLite kapt af bij conversie naar een geheel getal.TRUNC(2.97, 1) geeft 2,9 in PostgreSQL, terwijl ROUND(2.97, 1) voor dat exacte decimale getal 3,0 geeft.Afronding van het eindresultaat
Afrondingsverschil
Aggregatie-expressie
SUM(amount - discount) berekent de aftrekking per rij voordat de resultaten die niet NULL zijn worden opgeteld.Aggregatiefunctie
SUM(amount) om veel bestelbedragen om te zetten in één totaal voor de geselecteerde periode.AVG
AVG(amount) geeft 97,5 voor acht bestellingen waarvan de bedragen optellen tot 780 en meet het gemiddelde bestelbedrag.C
CASE-categorie
CASE-expressie wordt toegekend en als basis voor een gegroepeerd rapport kan dienen.amount >= 100 plaatst een bestelling van precies 100 in de categorie met label “large”.CAST
REAL in SQLite maakt decimale deling mogelijk, terwijl een conversie naar NUMERIC een gehele waarde een geheel getal kan laten blijven.COALESCE
COALESCE(SUM(amount), 0) geeft nul weer wanneer lege invoer anders een NULL-totaal zou opleveren.COUNT(*)
COUNT(*) van acht, ook als bij één bestelling geen regio is vastgelegd.COUNT(column)
COUNT(discount) telt een bestelling met korting nul mee, maar laat een bestelling met korting NULL weg.COUNT(DISTINCT column)
COUNT(DISTINCT customer) voor het aantal klanten van wie een naam is vastgelegd, ook wanneer sommigen meerdere bestellingen plaatsen.D
Decimale operand
Detailniveau
DISTINCT
SUM(DISTINCT quantity) telt elk aantal eenmaal op, zodat herhaalde echte verkopen buiten het totaal kunnen blijven.Drijvendekommagetal
DOUBLE PRECISION in PostgreSQL kan 0,30000000000000004 tonen waar exacte decimale rekenkunde 0,3 geeft.F
FILTER bij een aggregatiefunctie
Functionele afhankelijkheid
G
Gehele deling
Gemiddelde per klant
Groepering op meerdere kolommen
Groeperingsexpressie
CASE wordt toegekend.Groeperingskolom
Groeperingsregel
Groepsvoorwaarde
GROUP BY
GROUP BY region kan dezelfde query voor elke regio een afzonderlijk aantal bestellingen en een afzonderlijk bedragentotaal berekenen.H
HAVING
HAVING SUM(amount) > 200 behoudt regio's op basis van hun totaal, zonder kleine bestellingen uit overgebleven groepen te verwijderen.I
Invoer met uitsluitend NULL-waarden
COUNT(x) nul is.COUNT(*) van vier en een COUNT(discount) van nul.IS NULL
WHERE region IS NULL selecteert bestellingen waarvan de regio niet is vastgelegd, zoals een bestelling van een klant met de naam Eli.J
Jaar-maandsleutel
K
Kengetal
L
Lege invoer
WHERE-voorwaarde geen overeenkomende records vindt.Logische verwerkingsvolgorde
WHERE vóór GROUP BY te volgen, begrijp je waarom het verwijderen van kleine bestellingen het latere gemiddelde van een regio verandert.M
MIN en MAX
MIN(order_date) vindt de vroegste datum wanneer de kolom datums of consistent opgemaakte ISO-datumtekst bevat.N
Niet-gegroepeerde, niet-geaggregeerde kolom
NULL
amount - discount NULL maken, waardoor de berekende waarde van die rij door SUM wordt overgeslagen.NULL-groep
NULLIF
NULLIF(COUNT(*), 0) maakt de noemer van een leeg rapport NULL en voorkomt zo een fout door deling door nul in PostgreSQL.NUMERIC en DECIMAL
O
ONLY_FULL_GROUP_BY
Opsporing van dubbele waarden
HAVING COUNT(*) > 1 gebruiken identificeert klanten met herhaalde bestelrecords.ORDER BY
ORDER BY total DESC geeft de grootste groepstotalen eerst weer nadat elke groep is berekend.P
Percentage binnen een groep
R
Rijvoorwaarde
amount >= 60 kan de ene bestelling uit East behouden en een andere verwijderen voordat een regionale samenvatting bestaat.ROUND
ROUND(AVG(amount), 2) rondt het voltooide gemiddelde af op twee decimalen en laat de eerdere berekening intact.S
SELECT-alias
ORDER BY kan worden gebruikt; het gebruik elders verschilt per dialect.ORDER BY total, maar vereist dat de aggregatie-expressie wordt uitgeschreven in een HAVING op hetzelfde niveau.Sorteerregels (collation)
MIN-query gelijk blijven.SUM
SUM(quantity * unit_price) telt de omzetten per rij op nadat elk aantal met de bijbehorende prijs is vermenigvuldigd.U
Unieke combinatie
V
Vergelijking zonder afronding
HAVING AVG(amount) >= 86.67 als de exacte waarde kleiner is.Voorwaardelijk totaal
CASE-expressie die nul teruggeeft voor rijen die niet voldoen.CASE het bedrag zelf terug dat voldoet; 1 teruggeven zou in plaats daarvan bestellingen tellen.Voorwaardelijke aggregatie
Voorwaardelijke telling
COUNT NULL te laten teruggeven.COUNT(CASE WHEN amount >= 100 THEN 1 END) telt grote bestellingen en slaat de NULL-resultaten over van rijen die niet voldoen.W
Waarde halverwege twee afrondingsuitkomsten
NUMERIC-afronding in PostgreSQL rondt 2,5 af naar 3 en -2,5 naar -3, beide van nul af.WHERE
WHERE voordat het maandtotalen berekent.Over deze les
Door StudeliFout melden
Maak je eigen Studiemateriaal
Maak van je aantekeningen, slides en documenten Leermodules, Oefenvragen, Flashcards en 6 andere tools.