SQL GROUP BY: aggregatie en groepering

Leer vragen over samenvattingen van een databasetabel te beantwoorden: hoeveel, hoe groot het totaal, wat is het gemiddelde en wat zijn de kleinste en grootste waarden? Gebruik COUNT, SUM, AVG, MIN en MAX, groepeer rijen met GROUP BY voor één resultaat per categorie en behoud alleen de groepen die je nodig hebt met HAVING. Je leert ook hoe ontbrekende waarden en gehele deling resultaten veranderen, hoe je gemiddelden en percentages afrondt en hoe je controleert of een aggregatiequery de juiste getallen oplevert. De voorbeelden gebruiken standaard-SQL die in SQLite en PostgreSQL werkt. Waar verschillen in MySQL, SQL Server en Oracle van belang zijn, worden die aangegeven.

BeginnerLes 4 van 6 in SQL: de basis

Wat je leert

  1. 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 waarden
      Gebruik 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 waarden
      Kies tussen COUNT(*), COUNT(column) en COUNT(DISTINCT column) en weet hoe elk omgaat met herhaalde en ontbrekende waarden.
    • Voorspel hoe NULL-waarden aggregaties beïnvloeden
      Weet dat aggregatiefuncties NULL-waarden overslaan, voorspel de resultaten bij lege invoer en vervang NULL door een standaardwaarde als de vraag daarom vraagt.
  2. 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 BY
      Verdeel 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 query
      Weet 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 waarden
      Groepeer rijen op combinaties van kolommen en op expressies zoals de maand van een datum of een CASE-categorie, en lees het gedetailleerdere resultaat.
  3. 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 voldoen
      Schrijf HAVING-voorwaarden op aggregatiewaarden, ook op aggregaties die niet worden weergegeven, om een gegroepeerd resultaat te filteren.
    • Kies tussen WHERE en HAVING
      Gebruik de logische volgorde van een query om te bepalen of een voorwaarde rijen of groepen filtert en voorspel hoe die keuze het resultaat verandert.
  4. 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 percentages
      Herken 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 af
      Rond gemiddelden, totalen en percentages af met ROUND, rond op het juiste moment af en houd rekening met de verschillen tussen SQLite en PostgreSQL.
  5. 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 CASE
      Plaats 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 deze
      Zet een bedrijfsvraag stap voor stap om in een gegroepeerde query, voorkom dat je detailniveaus verwart en controleer of de getallen kloppen.

SQL GROUP BY: uitleg

5 hoofdstukken

1

Vat 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_idcustomerregionamountquantitydiscountorder_date
1AnaEast1202102026-01-05
2BenWest801NULL2026-01-17
3AnaEast45352026-02-02
4ChenNorth2004NULL2026-02-14
5BenWest60102026-02-20
6DaraEast952NULL2026-03-03
7ChenNorth1505152026-03-09
8EliNULL301NULL2026-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.
  • WHERE selecteert de rijen die de aggregatiefunctie gebruikt.
  • Bereken de bijdrage van elke rij binnen SUM wanneer waarden gekoppeld moeten blijven.
  • MIN en MAX volgen 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
ExpressieWat 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.
  • COUNT geeft 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 COALESCE binnen een functie verandert de invoer; een functie eromheen verandert een resultaat dat NULL is.
  • Lege invoer geeft nul voor COUNT en NULL voor de andere vier aggregatiefuncties.
  • NULL binnen een rekenkundige expressie kan de bijdrage van een rij weglaten.
2

Groepeer 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 BY kiest.
  • Alle NULL-groeperingswaarden vormen samen één groep.
  • Gebruik ORDER BY voor 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 customer voor éé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 HAVING en ORDER 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 BY maakt geen ontbrekende combinaties met aantallen van nul aan.
  • De volgorde van groeperingskolommen bepaalt de uitvoervolgorde niet.
3

Filter 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

  • HAVING behoudt of verwijdert voltooide groepen.
  • Een aggregatiefunctie in HAVING hoeft niet in SELECT te staan.
  • Combineer groepstoetsen met AND, OR en NOT.
  • Herhaal aggregatie-expressies in HAVING voor 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:

  1. FROM levert de rijen.
  2. WHERE behoudt rijen die aan de voorwaarde voldoen.
  3. GROUP BY vormt groepen en aggregatiefuncties berekenen hun kengetallen.
  4. HAVING behoudt groepen die aan de voorwaarde voldoen.
  5. SELECT levert de uitvoerwaarden; DISTINCT verwijdert zo nodig dubbele uitvoerrijen.
  6. ORDER BY sorteert het resultaat en LIMIT behoudt het gevraagde aantal rijen.

De database kan de interne uitvoering anders indelen.

Plaats elke voorwaarde op het juiste niveau
VraagClausule
Bestellingen met amount >= 60WHERE
Bestellingen in een gegeven datumbereikWHERE
Regio's met SUM(amount) > 200HAVING
Klanten met meer dan één bestellingHAVING 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

  • WHERE verandert de invoer van aggregatiefuncties; HAVING filtert 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.
4

Bereken 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
DatabaseGedrag om op te letten
SQLiteGehele deling kapt decimalen af; AVG geeft een drijvendekommagetal terug.
PostgreSQLGehele deling kapt decimalen af; AVG van gehele invoer of NUMERIC-invoer geeft NUMERIC terug.
SQL ServerGehele 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 NULLIF om 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 NUMERIC voor ROUND met twee argumenten.
  • Negatieve afrondingsposities en conversies naar gehele getallen verschillen per database.
5

Beantwoord 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 0 werkt 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 FILTER bij een aggregatiefunctie verandert alleen de invoer van die functie.
  • Gebruik IS NULL voor 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?”

  1. De kengetallen zijn COUNT(*) en AVG(amount).
  2. Het detailniveau, oftewel de betekenis van één resultaatrij, is één kalendermaand.
  3. De rijvoorwaarde behoudt datums in 2026.
  4. De groepsvoorwaarde vereist minstens drie bestellingen.
  5. 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 HAVING verwijdert.
  • 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

5 Walkthroughs

1

Zet bestelrijen om in betrouwbare samenvattende getallen

13 stappen
Kies aggregatiefuncties en tellingen en volg daarna de effecten van ontbrekende waarden.
  1. 1
    IntroductieLees 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.

  2. 2
    UitlegCombineer de bedragen

    Een aggregatie combineert waarden uit meerdere rijen tot één samenvatting. SUM(amount) telt de bedragen op, AVG(amount) bepaalt hun gemiddelde en MIN(amount) en MAX(amount) vinden de uiterste waarden. Zonder GROUP BY vormen alle bestellingen die aan de voorwaarden voldoen één groep. Je kunt meerdere aggregatiefuncties samen selecteren omdat ze elk dezelfde groep invoerrijen beschrijven.

  3. 3
    VoorbeeldBereken éé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.

  4. 4
    VoorbeeldKies 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.

  5. 5
    UitdagingHoud 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.

  6. 6
    UitlegTel 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.

  7. 7
    VoorbeeldTel de ontbrekende categorie

    De regiokolom heeft acht rijen maar slechts zeven vastgelegde waarden. COUNT(*) is acht, COUNT(region) is zeven en COUNT(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.

  8. 8
    UitdagingKies de juiste telling

    Een kolom voor kortingsbonnen bevat NULL, 0, 8, 8 en 0. Welke waarden geven COUNT(*), COUNT(coupon) en COUNT(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.

  9. 9
    UitlegLaat 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.

  10. 10
    VoorbeeldPlaats 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. COALESCE rond de voltooide som kan weggelaten bijdragen van rijen niet terugbrengen.

  11. 11
    UitdagingVerwerk een groep zonder bekende waarden

    Een query behoudt drie rijen waarvan de bedragen allemaal NULL zijn. Wat geven COUNT(*), COUNT(amount) en SUM(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.

  12. 12
    UitdagingControleer 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 en COUNT(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.

  13. 13
    SamenvattingHoud 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.

2

Maak een rapport op het juiste detailniveau

14 stappen
Groepeer op categorieën, herstel dubbelzinnige kolommen en maak gecombineerde of berekende groepen.

Sla deze les op om elke Walkthrough stap voor stap te volgen.

  1. 1
    IntroductieBepaal waar een resultaatrij voor staat
  2. 2
    UitlegVerzamel rijen per regio
  3. 3
    VoorbeeldHoud de NULL-groep zichtbaar
  4. 4
    TipSorteer voordat je de hoogste rijen behoudt
  5. 5
    UitdagingVoorspel hoeveel groepen overblijven
  6. 6
    UitlegLeg uit waarom een naam dubbelzinnig is
  7. 7
    VoorbeeldPas het rapport aan de vraag aan
  8. 8
    TipHerken een resultaat dat door soepel gedrag ontstaat
  9. 9
    UitdagingKies een betekenisvolle oplossing
  10. 10
    VoorbeeldSplits een groep op een tweede waarde
  11. 11
    UitlegMaak een label voor een kalendermaand
  12. 12
    UitdagingVind de groeperingsexpressie
  13. 13
    UitdagingControleer het detailniveau en de labels van het rapport
  14. 14
    SamenvattingLees elke rij als één groep
3

Plaats filters vóór of na aggregatie

10 stappen
Volg WHERE en HAVING door een rapport en voorspel hoe hun plaats het antwoord verandert.

Sla deze les op om elke Walkthrough stap voor stap te volgen.

  1. 1
    IntroductieMaak onderscheid tussen populatie en selectie
  2. 2
    UitlegToets de voltooide groep
  3. 3
    VoorbeeldGebruik een telling zonder die weer te geven
  4. 4
    UitdagingControleer de werkelijke waarde die wordt vergeleken
  5. 5
    UitlegVolg de logische fasen van het resultaat
  6. 6
    VoorbeeldVerwijder eerst kleine bestellingen
  7. 7
    VoorbeeldVerwijder daarna kleine groepstotalen
  8. 8
    UitdagingOnderzoek een veranderde vraag
  9. 9
    UitdagingCombineer rij- en groepsbeperkingen
  10. 10
    SamenvattingLaat de voorwaarde de fase bepalen
4

Behoud decimalen en rond het eindresultaat af

11 stappen
Volg numerieke typen, voorkom noemers van nul en rond aggregaties in de juiste fase af.

Sla deze les op om elke Walkthrough stap voor stap te volgen.

  1. 1
    IntroductieHoud berekening en weergave gescheiden
  2. 2
    VoorbeeldZoek waar het gedeelte achter de komma verdwijnt
  3. 3
    UitlegVoeg de decimale operand vroeg toe
  4. 4
    TipBeveilig een lege noemer
  5. 5
    UitdagingHerstel een percentage-expressie
  6. 6
    UitlegRond het berekende gemiddelde af
  7. 7
    VoorbeeldZie hoe vroeg afronden een totaal verandert
  8. 8
    UitdagingControleer een verschil tussen dialecten
  9. 9
    VerbandKies het type voor exacte bedragen
  10. 10
    UitdagingControleer het type vóór het afronden
  11. 11
    SamenvattingVolg het getal door elke fase
5

Stel een bedrijfssamenvatting op en controleer deze

13 stappen
Maak kengetallen voor deelverzamelingen, kies een detailniveau voor het rapport en vat gegroepeerde resultaten samen op twee queryniveaus.

Sla deze les op om elke Walkthrough stap voor stap te volgen.

  1. 1
    IntroductieHoud alle bestellingen en geselecteerde bestellingen bij elkaar
  2. 2
    UitlegLaat rijen die niet voldoen NULL bijdragen
  3. 3
    VoorbeeldHoud de volledige groep beschikbaar
  4. 4
    VoorbeeldTel het bedrag of één op
  5. 5
    UitdagingBehoud de noemer voor een deelverzameling
  6. 6
    UitlegVertaal de zakelijke formulering
  7. 7
    VoorbeeldMaak het maandresultaat
  8. 8
    TipControleer voordat je groepen verbergt
  9. 9
    UitlegVerander de invoereenheid voor een gemiddelde
  10. 10
    VoorbeeldLees de twee queryniveaus
  11. 11
    UitdagingKies de juiste eenheid voor het gemiddelde
  12. 12
    UitdagingTel alleen klantgroepen die voldoen
  13. 13
    SamenvattingControleer de populatie en het detailniveau

SQL GROUP BY: oefenvragen

40 Oefenvragen in 4 sets

Set 1: Lees tellingen, groepen en berekeningen10 Oefenvragen

Vraag 1 van 10

Een gegroepeerd rapport heeft de teamtotalen Red 180, Blue 260 en Green 200. Welke teams blijven over na HAVING SUM(amount) > 200?
  1. Blue
  2. Blue en Green
  3. Red en Blue
  4. Green
Toon antwoordVerberg antwoord
Antwoord: A
Alleen Blue heeft een totaal dat strikt boven 200 ligt. Green is gelijk aan de grenswaarde en voldoet daarom niet aan de groter-dantoets; het zou wel voldoen aan >= 200. HAVING past deze vergelijking toe op elk voltooid teamtotaal en behoudt of verwijdert dus elk volledig teamresultaat.

Vraag 2 van 10

Een leveringentabel legt de afstanden 14, 22 en 35 vast. Welke waarde geeft SUM(distance) terug?
  1. 35
  2. 23.67
  3. 71
  4. 3
Toon antwoordVerberg antwoord
Antwoord: C
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

Vijf verzoeken hebben de statuswaarden closed, open, closed, open en open. Wat geeft COUNT(CASE WHEN status = 'closed' THEN 1 ELSE 0 END) terug?
  1. 5
  2. 2
  3. 3
  4. 0
Toon antwoordVerberg antwoord
Antwoord: A
Elk CASE-resultaat is een vastgelegde waarde: verzoeken met status closed leveren 1 op en verzoeken met status open 0. COUNT telt beide en geeft vijf. Om alleen de twee verzoeken met status closed te tellen, laat je ELSE weg zodat rijen die niet voldoen NULL opleveren, of tel je de indicatoren met enen en nullen op met SUM.

Vraag 4 van 10

Vier leveringen hebben vertragingen van 6, NULL, 10 en 8 minuten. Een ontbrekende vertraging betekent dat die niet is gemeten. Welk gemiddelde geeft AVG(delay) terug?
  1. 6
  2. 24
  3. 10
  4. 8
Toon antwoordVerberg antwoord
Antwoord: D
De drie gemeten vertragingen zijn samen 24 minuten en 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

Een dienstentabel bevat de afdelingswaarden Sales, Support, Sales, NULL en NULL. Hoeveel rijen geeft SELECT department, COUNT(*) FROM shifts GROUP BY department terug?
  1. 5
  2. 3
  3. 2
  4. 4
Toon antwoordVerberg antwoord
Antwoord: B
De query vormt één groep voor Sales, één voor Support en één voor de ontbrekende afdelingswaarde, dus geeft drie rijen terug. NULL-groeperingswaarden horen bij elkaar; elke NULL als afzonderlijke groep behandelen zou een extra resultaatrij maken die SQL niet oplevert.

Vraag 6 van 10

Een onderdelentabel heeft meerdere leveranciers per categorie. Het rapport heeft één rij per categorie nodig en het aantal verschillende leveranciers daarvan. Welke SELECT-lijst past bij FROM parts GROUP BY category?
  1. category, supplier, COUNT(*)
  2. category, COUNT(DISTINCT supplier)
  3. category, COUNT(supplier)
  4. category, MIN(supplier)
Toon antwoordVerberg antwoord
Antwoord: B
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

Een betalingentabel in PostgreSQL heeft een DATE-kolom paid_on met records van 2024 tot en met 2026. Welke groeperingsexpressie houdt elke kalendermaand gescheiden?
  1. EXTRACT(MONTH FROM paid_on)
  2. EXTRACT(YEAR FROM paid_on)
  3. paid_on
  4. to_char(paid_on, 'YYYY-MM')
Toon antwoordVerberg antwoord
Antwoord: D
De jaar-maandexpressie geeft elke kalendermaand een eigen sleutel en houdt juni in verschillende jaren gescheiden. Een maandnummer alleen zou die junimaanden samenvoegen, terwijl groeperen op de volledige datum een maand in daggroepen zou splitsen en het gevraagde detailniveau zou veranderen.

Vraag 8 van 10

Een PostgreSQL-query selecteert categorie en totale kosten, groepeert alleen op categorie en gebruikt 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?
  1. Voeg supplier toe aan GROUP BY.
  2. Gebruik ORDER BY supplier DESC.
  3. Gebruik ORDER BY SUM(cost) DESC.
  4. Voeg supplier toe aan de SELECT-lijst.
Toon antwoordVerberg antwoord
Antwoord: C
Sorteren op SUM(cost) gebruikt één vastgelegd kengetal voor elke categoriegroep en behoudt één rij per categorie. Een gewone leverancier kan een groep met meerdere leveranciers niet ordenen. Supplier toevoegen aan GROUP BY zou de syntaxis geldig maken maar categorieën splitsen, waardoor het gevraagde detailniveau van het rapport verandert.

Vraag 9 van 10

In SQLite tellen gehele aantallen op tot 23 over zes rijen. Wat geeft SUM(quantity) / COUNT(*) * 1.0 terug?
  1. 3.0
  2. 3.8333333333333335
  3. 4.0
  4. 23.0
Toon antwoordVerberg antwoord
Antwoord: A
Gehele deling vindt eerst plaats: 23 gedeeld door zes wordt afgekapt tot drie. Dat resultaat vermenigvuldigen met 1,0 geeft 3,0 en kan het verloren gedeelte achter de komma niet herstellen. Om de decimalen van het gemiddelde te behouden, voeg je vóór de deling de decimale operand toe met 1.0 * SUM(quantity) / COUNT(*).

Vraag 10 van 10

Een SQLite-tabel heeft drie vergoedingen van 0,26. Een query selecteert ROUND(SUM(fee), 1) maar behoudt de totale groep alleen met HAVING SUM(fee) >= 0.8. Welk resultaat geeft de query terug?
  1. Eén rij met 0,8.
  2. Eén rij met 0,9.
  3. Eén rij met NULL.
  4. Geen rij.
Toon antwoordVerberg antwoord
Antwoord: D
De vergoedingen zijn samen 0,78, wat na afronding als 0,8 zou worden weergegeven. HAVING vergelijkt de niet-afgeronde som met 0,8, zodat de groep niet voldoet en geen rij verschijnt. Als je de afgeronde weergave als getoetste waarde zou behandelen, zou je een groep accepteren waarvan het werkelijke totaal onder de grenswaarde ligt.
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

Een tickettabel heeft de prioriteitswaarden 0, NULL, 2, 2 en NULL. Wat geeft COUNT(priority) terug?
  1. 5
  2. 3
  3. 2
  4. 1
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 2 van 10

Een work_log-tabel heeft de kolommen consultant, year en hours. Een rapport heeft één totaal aantal uren per consultant voor 2025 nodig en behoudt alleen totalen boven 120. Welke queryvorm beantwoordt die vraag?
  1. WHERE year = 2025 AND hours > 120 GROUP BY consultant
  2. GROUP BY consultant, hours HAVING SUM(hours) > 120
  3. WHERE hours > 120 GROUP BY consultant, year
  4. WHERE year = 2025 GROUP BY consultant HAVING SUM(hours) > 120
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 3 van 10

Een tabel slaat leverdatums op als ISO-tekst: “2025-12-28”, “2026-01-04” en “2025-02-19”. Wat geven MIN(delivery_date) en MAX(delivery_date) in die volgorde terug?
  1. 2025-02-19 en 2026-01-04
  2. 2025-12-28 en 2026-01-04
  3. 2026-01-04 en 2025-02-19
  4. 2026-01-04 en 2025-12-28
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 4 van 10

Een SQLite-tabel heeft de paren (city, agent) (A, Jo), (A, Jo), (A, Kai), (NULL, Lee) en (NULL, Lee). Wat geeft SELECT COUNT(*) FROM (SELECT DISTINCT city, agent FROM visits) AS pairs terug?
  1. 2
  2. 4
  3. 3
  4. 5
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 5 van 10

Vier reparaties hebben de waarden (kosten, tegoed) (50, 5), (80, NULL), (40, 0) en (30, NULL). NULL betekent geen tegoed. Wat zijn SUM(cost - credit) en de bedoelde totale nettokosten, in die volgorde?
  1. 195 en 195
  2. 85 en 85
  3. 115 en 195
  4. 85 en 195
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 6 van 10

De klanttotalen zijn Ali 90, Bea 120, Cam 120 en Dev 75. Welke rijen behoudt ORDER BY total DESC, customer ASC LIMIT 2, als de namen alfabetisch worden gesorteerd?
  1. Ali 90 en Bea 120
  2. Bea 120 en Cam 120
  3. Cam 120 en Bea 120
  4. Bea 120 en Ali 90
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 7 van 10

Een vergoedingentabel bevat drie waarden van 0,36. Wat leveren ROUND(SUM(fee), 1) en SUM(ROUND(fee, 1)) in die volgorde op, als je kleine weergaveafwijkingen door drijvendekommagetallen negeert?
  1. 1,2 en 1,1
  2. 1,1 en 1,1
  3. 1,1 en 1,2
  4. 1,2 en 1,2
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 8 van 10

Een tabel bevat de paren (locatie, medewerker) (A, Ren), (A, Ren), (A, Sol), (B, Ren), (NULL, Sol) en (NULL, Sol). Hoeveel groepen ontstaan bij groeperen op locatie en vervolgens bij groeperen op locatie en medewerker?
  1. 3 en 4
  2. 3 en 6
  3. 2 en 3
  4. 3 en 3
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 9 van 10

Een rooster heeft de trainingswaarden Safety, Safety, Tools, Tools, Tools en First Aid. Wat geeft SELECT training FROM roster GROUP BY training HAVING COUNT(*) >= 3 terug?
  1. Safety en Tools
  2. Tools
  3. Tools en First Aid
  4. Geen rijen
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 10 van 10

Team A heeft bedragen 20, 80 en 100; team B heeft 60 en 90. Wat blijft over na WHERE amount >= 60 GROUP BY team HAVING AVG(amount) > 80?
  1. B met gemiddelde 75.
  2. A met gemiddelde ongeveer 66,67.
  3. A met gemiddelde 90.
  4. A met 90 en B met 75.
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

Wat geeft SELECT 17 / 5 terug in SQLite?
  1. 3.4
  2. 4
  3. 0
  4. 3
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 2 van 10

Een query groepeert declaraties op team maar selecteert een gewone medewerkersnaam. Elk team heeft meerdere medewerkers. SQLite toont een naam en PostgreSQL weigert de query. Wat verklaart het verschil?
  1. SQLite groepeert automatisch op medewerker; PostgreSQL vereist een expliciete groepering.
  2. SQLite staat een niet-gegroepeerde, niet-geaggregeerde kolom toe; de naam beschrijft niet het hele team.
  3. SQLite geeft alfabetisch de eerste medewerker terug; PostgreSQL vereist een expliciete sortering.
  4. SQLite verwijdert extra medewerkers vóór het groeperen; PostgreSQL behoudt elke medewerker.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 3 van 10

Locatie L heeft bedragen 30, 50 en 80; locatie M heeft 20 en 40. Je hebt per locatie het percentage bestellingen van minstens 60 nodig, inclusief locaties zonder zulke bestellingen. Welke percentages moeten verschijnen?
  1. L 100,0%; M ontbreekt.
  2. L 20,0%; M 0,0%.
  3. L 33,3%; M 0,0%.
  4. L 50,0%; M 0,0%.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 4 van 10

Klant Inez heeft bedragen 20, 30 en 50; Omar heeft 200. Wat zijn het gemiddelde bestelbedrag en het gemiddelde totale bedrag per klant, in die volgorde?
  1. 75 en 150
  2. 150 en 75
  3. 75 en 100
  4. 100 en 150
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 5 van 10

Een voorraadtabel heeft de rijen (afdeling, aantal, prijs) (A, 2, 7), (A, 3, 4) en (B, 5, 9). Wat geeft SELECT SUM(quantity * price) FROM stock WHERE department = 'A' terug?
  1. 55
  2. 71
  3. 26
  4. 14
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 6 van 10

Een regiokolom bevat NULL, West, West, East en NULL. Wat geeft COUNT(DISTINCT region) terug?
  1. 2
  2. 3
  3. 5
  4. 1
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 7 van 10

Geen rijen in jobs voldoen aan state = 'queued'. Wat geeft SELECT team, COALESCE(SUM(hours), 0) FROM jobs WHERE state = 'queued' GROUP BY team terug?
  1. Eén rij met NULL-team en nul.
  2. Eén rij met NULL-team en NULL.
  3. Eén rij met nultotaal voor elk team.
  4. Geen rijen.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 8 van 10

Een tabel heeft de gebiedswaarden North, NULL, South, NULL en North. Wat zijn na WHERE area IS NOT NULL GROUP BY area de groepsaantallen?
  1. North 2; South 1; NULL 2.
  2. North 2; South 1.
  3. North 1; South 1.
  4. North 3; South 2.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 9 van 10

Een rapport heeft gemiddelde factuurbedragen per kantoor nodig, met alleen facturen uit 2025, en toont alleen kantoren met meer dan vijf facturen die voldoen. Waar horen de datumtoets en de aantaltoets?
  1. Beide toetsen in WHERE.
  2. Datum in HAVING; aantal in WHERE.
  3. Beide toetsen in HAVING.
  4. Datum in WHERE; aantal in HAVING.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 10 van 10

Bestellingen hebben de waarden (datum, bedrag) (2025-01-10, 90), (2026-01-12, 140), (2026-01-20, 60) en (2026-02-03, 110). Groepeer op jaar-maand en op CASE WHEN amount >= 100 THEN 'large' ELSE 'small' END. Hoeveel groepen ontstaan?
  1. 4
  2. 3
  3. 2
  4. 5
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

Klant X heeft bedragen 40 en 70, Y heeft 60, 60 en 10 en Z heeft 150. Hoeveel klanten hebben minstens twee bestellingen en een totaal boven 120?
  1. 2
  2. 3
  3. 5
  4. 1
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 2 van 10

Een rapport groepeert een boekingentabel op ruimte. Welke HAVING-voorwaarde behoudt ruimtes met minstens vier boekingen?
  1. HAVING COUNT(*) >= 4
  2. HAVING COUNT(*) > 4
  3. HAVING COUNT(*) = 4
  4. HAVING COUNT(*) <= 4
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 3 van 10

Vestiging A heeft bedragen 10, 40 en 70; vestiging B heeft 30 en 50. Vergelijk groeperen na WHERE amount >= 30 met alle rijen groeperen en HAVING MIN(amount) >= 30 gebruiken. Welke gemiddelden verschijnen?
  1. WHERE: A 40 en B 40; HAVING: alleen B 40.
  2. WHERE: A 55 en B 40; HAVING: A 55 en B 40.
  3. WHERE: A 55 en B 40; HAVING: alleen B 40.
  4. WHERE: alleen B 40; HAVING: A 40 en B 40.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 4 van 10

Een ongegroepeerd rapport kan geen invoerrijen hebben. Welke expressie geeft het percentage rijen met een vastgelegde waarde, behoudt decimalen en geeft bij een lege populatie NULL terug in zowel SQLite als PostgreSQL?
  1. 100 * COUNT(value) / NULLIF(COUNT(*), 0)
  2. 100.0 * COUNT(value) / NULLIF(COUNT(*), 0)
  3. 100.0 * COUNT(value) / COALESCE(COUNT(*), 1)
  4. 100.0 * COUNT(*) / NULLIF(COUNT(value), 0)
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 5 van 10

In PostgreSQL is temperature van het type DOUBLE PRECISION. Hoe rond je het gemiddelde af op twee decimalen?
  1. ROUND(AVG(temperature), 2)
  2. CAST(ROUND(AVG(temperature)) AS NUMERIC)
  3. ROUND(CAST(AVG(temperature) AS INTEGER), 2)
  4. ROUND(CAST(AVG(temperature) AS NUMERIC), 2)
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 6 van 10

In PostgreSQL staat COUNT(*) FILTER (WHERE paid = 1) naast COUNT(*) in een gegroepeerde query zonder WHERE-clausule. Wat beperkt het filter?
  1. Elke aggregatiefunctie in de groep.
  2. Alleen de uiteindelijke resultaatweergave.
  3. Alleen de aggregatiefunctie voor het aantal betaalde gevallen.
  4. Elke rij voordat groepen worden gevormd.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 7 van 10

Een query behoudt vier rijen met de waarden NULL, NULL, NULL en NULL. Wat zijn COUNT(*), COUNT(value) en MAX(value), in die volgorde?
  1. 4, 0, NULL
  2. 0, 0, NULL
  3. 4, 4, NULL
  4. 4, 0, 0
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 8 van 10

Een bezoekentabel heeft de paren (klant, zone) (Jo, East), (Jo, East), (Kai, West), (Kai, North), (Lee, NULL) en (Lee, NULL). Hoe verandert het aantal groepen als je zone toevoegt aan de groepering op klant?
  1. Het blijft drie.
  2. Het stijgt van drie naar vier.
  3. Het stijgt van drie naar zes.
  4. Het stijgt van drie naar vijf.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 9 van 10

Een gegroepeerd rapport bevat de zones East, West en NULL. Een rijfilter is WHERE zone <> 'West'. Welke zonegroepen kunnen overblijven?
  1. East en NULL.
  2. East en West.
  3. Alleen East.
  4. Alleen NULL.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Vraag 10 van 10

In een SQLite-besteltabel heeft mei 2025 de bedragen 20 en 100, mei 2026 heeft 50 en 70 en juni 2026 heeft 200. Een rapport moet alleen maanden van 2026 met minstens twee bestellingen tonen, met het afgeronde gemiddelde bedrag. Welk resultaat past bij de vraag?
  1. 2026-05: vier bestellingen, gemiddelde 60,00.
  2. 2026-05: twee bestellingen, gemiddelde 60,00.
  3. 2026-06: één bestelling, gemiddelde 200,00.
  4. 2026-05: twee bestellingen, gemiddelde 120,00.
Toon antwoordVerberg antwoord

Sla deze les op om dit antwoord te zien.

Kom je niet uit je eigen opgave? Huiswerkhulp

Kernbegrippen

58 Kernbegrippen, elk met een definitie

A

Aansluitcontrole
Een aansluitcontrole controleert of groepsaantallen en -totalen optellen tot de overeenkomstige ongegroepeerde kengetallen over dezelfde gefilterde populatie.
Voer de query eerst zonder HAVING uit, zodat uitgesloten groepen geen verschil tussen het rapport en het invoertotaal veroorzaken.
Aanvullende sorteerkolom
Een aanvullende sorteerkolom is een extra sorteersleutel die rijen een reproduceerbare volgorde geeft wanneer hun eerdere sorteerwaarden gelijk zijn.
ORDER BY total DESC, customer geeft gelijke klanttotalen een stabiele volgorde voordat een beperking wordt toegepast.
Afgeleide tabel
Een afgeleide tabel is het resultaat van een query dat in FROM wordt gebruikt, zodat een tweede query de rijen van de eerste query kan samenvatten.
Een binnenste query maakt klanttotalen; een buitenste query gebruikt die totalen als invoer om hun gemiddelde te berekenen.
Afkappen
Afkappen verwijdert cijfers achter de komma zonder af te ronden; PostgreSQL biedt 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
Afronding van het eindresultaat vermindert de precisie na de volledige aggregatieberekening en voorkomt zo opgestapelde veranderingen door eerst elke invoerwaarde af te ronden.
Drie vergoedingen van 0,44 zijn samen 1,32 vóór afronding naar 1,3; elke vergoeding eerst afronden zou een totaal van 1,2 opleveren.
Afrondingsverschil
Een afrondingsverschil is een verschil door vermindering van precisie, bijvoorbeeld wanneer afgeronde delen niet meer optellen tot een afgerond geheel.
Drie gelijke procentuele aandelen, weergegeven op één decimaal, tellen op tot 99,9%, hoewel de exacte aandelen samen 100% vormen.
Aggregatie-expressie
Een aggregatie-expressie past een samenvattende functie toe op een kolom of berekening per rij, zoals het optellen van het aantal maal de prijs van elke rij.
SUM(amount - discount) berekent de aftrekking per rij voordat de resultaten die niet NULL zijn worden opgeteld.
Aggregatiefunctie
Een aggregatiefunctie combineert waarden uit meerdere invoerrijen tot één resultaat, zoals een aantal, som, gemiddelde of uiterste waarde.
Een verkooprapport gebruikt SUM(amount) om veel bestelbedragen om te zetten in één totaal voor de geselecteerde periode.
AVG
AVG is een aggregatiefunctie die het rekenkundig gemiddelde berekent van invoerwaarden die niet NULL zijn, waarbij elke vastgelegde waarde eenmaal meetelt.
AVG(amount) geeft 97,5 voor acht bestellingen waarvan de bedragen optellen tot 780 en meet het gemiddelde bestelbedrag.

C

CASE-categorie
Een CASE-categorie is een label dat door voorwaarden in een CASE-expressie wordt toegekend en als basis voor een gegroepeerd rapport kan dienen.
Een grenswaarde van amount >= 100 plaatst een bestelling van precies 100 in de categorie met label “large”.
CAST
CAST converteert een waarde naar een gevraagd SQL-type, met effecten die afhangen van het doeltype en de database-engine.
Een conversie naar REAL in SQLite maakt decimale deling mogelijk, terwijl een conversie naar NUMERIC een gehele waarde een geheel getal kan laten blijven.
COALESCE
COALESCE is een functie die het eerste argument teruggeeft dat niet NULL is, zodat je een gekozen standaardwaarde voor invoer of een eindresultaat kunt gebruiken.
COALESCE(SUM(amount), 0) geeft nul weer wanneer lege invoer anders een NULL-totaal zou opleveren.
COUNT(*)
COUNT(*) is de aggregatievorm die elke invoerrij telt, inclusief rijen met ontbrekende waarden in één of meer kolommen.
Een tabel met acht bestellingen heeft een COUNT(*) van acht, ook als bij één bestelling geen regio is vastgelegd.
COUNT(column)
COUNT(column) telt rijen met een waarde die niet NULL is in de genoemde kolom; herhaalde waarden en vastgelegde nullen tellen mee.
COUNT(discount) telt een bestelling met korting nul mee, maar laat een bestelling met korting NULL weg.
COUNT(DISTINCT column)
COUNT(DISTINCT column) telt de verschillende waarden van een kolom die niet NULL zijn, waarbij herhaalde vastgelegde waarden slechts eenmaal worden geteld.
Gebruik COUNT(DISTINCT customer) voor het aantal klanten van wie een naam is vastgelegd, ook wanneer sommigen meerdere bestellingen plaatsen.

D

Decimale operand
Een decimale operand is een numerieke invoerwaarde die ervoor zorgt dat een berekening het gedeelte achter de komma behoudt wanneer je die vóór een gehele deling toevoegt.
De som vóór het delen met 1,0 vermenigvuldigen behoudt het gedeelte achter de komma van een gemiddelde dat uit totalen is opgebouwd.
Detailniveau
Het detailniveau van een rapport is wat één uitvoerrij vertegenwoordigt, zoals een klant of maand, en bepaalt welke groepering nodig is.
Een rapport met één rij per klant heeft kengetallen op klantniveau nodig, ook wanneer de brontabel bestellingen vastlegt.
DISTINCT
DISTINCT verwijdert dubbele waarden of rijen in de fase waarin het wordt toegepast, bijvoorbeeld binnen een aggregatiefunctie of in de uitvoerlijst.
SUM(DISTINCT quantity) telt elk aantal eenmaal op, zodat herhaalde echte verkopen buiten het totaal kunnen blijven.
Drijvendekommagetal
Een drijvendekommagetal slaat veel decimale waarden als binaire benadering op, zodat sommige berekeningen kleine afrondingsafwijkingen kunnen tonen.
Een optelling met DOUBLE PRECISION in PostgreSQL kan 0,30000000000000004 tonen waar exacte decimale rekenkunde 0,3 geeft.

F

FILTER bij een aggregatiefunctie
Een FILTER bij een aggregatiefunctie beperkt de invoer voor één aggregatiefunctie, terwijl andere aggregatiefuncties in dezelfde query andere rijen kunnen gebruiken.
PostgreSQL kan binnen dezelfde groep een gefilterde telling van grote bestellingen naast een ongefilterde telling van alle bestellingen plaatsen.
Functionele afhankelijkheid
Een functionele afhankelijkheid houdt in dat de ene waarde een andere bepaalt, zoals een primaire sleutel van een bestelling de klant van die bestelling bepaalt.
PostgreSQL kan de klant selecteren wanneer de groepering de primaire sleutel van de besteltabel bevat.

G

Gehele deling
Gehele deling deelt gehele operanden en verwijdert in SQLite, PostgreSQL en SQL Server het gedeelte achter de komma.
In SQLite geeft 19 artikelen gedeeld door acht bestellingen met gehele operanden 2 in plaats van het gemiddelde 2,375.
Gemiddelde per klant
Een gemiddelde per klant geeft het totaal van elke klant één bijdrage, wat verschilt van het middelen van alle afzonderlijke bestelbedragen.
Wanneer vijf klanten acht bestellingen plaatsen met een totaal van 780, is hun gemiddelde per klant 156, hoewel het gemiddelde van de acht bestellingen 97,5 is.
Groepering op meerdere kolommen
Groepering op meerdere kolommen vormt een groep voor elke combinatie van groeperingswaarden die daadwerkelijk in de overgebleven invoerrijen voorkomt.
Groeperen op regio en klant geeft afzonderlijke resultaten voor Ana en Dara in East en houdt de bestellingen van Ana bij elkaar.
Groeperingsexpressie
Een groeperingsexpressie berekent uit elke rij een groeperingswaarde, zoals een kalendermaand of een categorie die door CASE wordt toegekend.
Een jaar-maandexpressie combineert bestellingen uit februari en houdt ze gescheiden van februari in een ander jaar.
Groeperingskolom
Een groeperingskolom levert de waarden die bepalen welke invoerrijen bij elkaar horen in een gegroepeerde aggregatiequery.
Als je klant als groeperingskolom kiest, gaat een rapport over klanten in plaats van over afzonderlijke bestellingen.
Groeperingsregel
De groeperingsregel vereist dat elke geselecteerde waarde door groepering of aggregatie een vastgelegde betekenis heeft voor de groep.
Een regio met meerdere klanten kan niet één gewone klantnaam leveren tenzij de query aangeeft hoe die wordt gekozen.
Groepsvoorwaarde
Een groepsvoorwaarde toetst een eigenschap van een voltooide groep, zoals of het aantal of gemiddelde aan een vereiste grenswaarde voldoet.
Een minimum van drie bestellingen per maand is een groepsvoorwaarde omdat daarvoor het voltooide maandaantal nodig is.
GROUP BY
GROUP BY is de clausule die invoerrijen verzamelt op basis van gelijke kolom- of expressiewaarden, zodat aggregatiefuncties eenmaal per groep kunnen worden toegepast.
Met GROUP BY region kan dezelfde query voor elke regio een afzonderlijk aantal bestellingen en een afzonderlijk bedragentotaal berekenen.

H

HAVING
HAVING is de clausule die groepen filtert op basis van hun groeperingswaarden of berekende aggregaties nadat die aggregaties bestaan.
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
Invoer met uitsluitend NULL-waarden heeft wel rijen maar geen vastgelegde waarden voor de expressie die wordt geaggregeerd, zodat COUNT(x) nul is.
Vier bestellingen met onbekende kortingen geven wanneer een filter alleen die bestellingen selecteert een COUNT(*) van vier en een COUNT(discount) van nul.
IS NULL
IS NULL is een SQL-test die waar is wanneer een waarde ontbreekt, zodat records met ontbrekende waarden expliciet kunnen worden geselecteerd of geteld.
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
Een jaar-maandsleutel identificeert een kalendermaand samen met het jaar en voorkomt dat dezelfde maand uit verschillende jaren wordt samengevoegd.
De labels “2025-01” en “2026-01” leveren afzonderlijke groepen op in een maandrapport dat beide jaren beslaat.

K

Kengetal
Een kengetal is de grootheid die een rapport berekent, zoals een aantal, totaal of gemiddelde, op het gekozen detailniveau van het rapport.
Een maandrapport over bestellingen kan het aantal bestellingen en het gemiddelde bedrag gebruiken als twee kengetallen voor dezelfde maandpopulatie.

L

Lege invoer
Lege invoer is een verzameling zonder rijen die een berekening ingaat, bijvoorbeeld wanneer een WHERE-voorwaarde geen overeenkomende records vindt.
Een ongegroepeerde telling van bestellingen uit South geeft nul terug wanneer elke bestelling in de tabel elders thuishoort.
Logische verwerkingsvolgorde
De logische verwerkingsvolgorde beschrijft de fasen die het resultaat van een query bepalen, waaronder het filteren van rijen vóór groepsberekeningen.
Door 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 en MAX zijn aggregatiefuncties die volgens de vergelijkingsregels van de database de kleinste en grootste invoerwaarden vinden die niet NULL zijn.
MIN(order_date) vindt de vroegste datum wanneer de kolom datums of consistent opgemaakte ISO-datumtekst bevat.

N

Niet-gegroepeerde, niet-geaggregeerde kolom
Een niet-gegroepeerde, niet-geaggregeerde kolom is een geselecteerde kolom in een aggregatiequery die geen groeperingskolom is en niet binnen een aggregatiefunctie staat.
SQLite kan één klant naast een regiototaal tonen, ook wanneer meerdere klanten aan die regio hebben bijgedragen.
NULL
NULL duidt een ontbrekende of onbekende SQL-waarde aan; rekenen ermee levert NULL op en het verschilt van nul of lege tekst.
Een onbekende korting kan amount - discount NULL maken, waardoor de berekende waarde van die rij door SUM wordt overgeslagen.
NULL-groep
Een NULL-groep bevat de rijen waarvan de groeperingswaarde ontbreekt; SQL plaatst die rijen samen in één resultaatgroep.
Meerdere bestellingen zonder regio delen één totaal dat kan worden weergegeven met een label zoals “Geen regio”.
NULLIF
NULLIF geeft NULL terug wanneer de twee argumenten gelijk zijn en anders het eerste argument, waardoor de functie bruikbaar is voor delers die nul kunnen zijn.
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
NUMERIC en DECIMAL bieden exacte decimale typen in PostgreSQL; in SQLite geven deze namen typeaffiniteit zonder exacte decimale opslag.
Voor exacte geldtotalen in SQLite voorkom je met hele centen dat je afhankelijk bent van waarden met decimalen die als binaire benaderingen zijn opgeslagen.

O

ONLY_FULL_GROUP_BY
ONLY_FULL_GROUP_BY is een MySQL-modus die gegroepeerde expressies weigert met niet-gegroepeerde waarden die niet door de groepering worden bepaald.
MySQL weigert normaal gesproken een willekeurige klant te selecteren wanneer de query de bestellingen alleen op regio groepeert.
Opsporing van dubbele waarden
Opsporing van dubbele waarden vindt herhaalde waarden door records op die waarden te groeperen en groepen met aantallen boven één te behouden.
Groeperen op klant en HAVING COUNT(*) > 1 gebruiken identificeert klanten met herhaalde bestelrecords.
ORDER BY
ORDER BY is de clausule die een bepaalde uitvoervolgorde opvraagt, waaronder het sorteren van gegroepeerde rijen op een aggregatie of de alias daarvan.
ORDER BY total DESC geeft de grootste groepstotalen eerst weer nadat elke groep is berekend.

P

Percentage binnen een groep
Een percentage binnen een groep meet een deelverzameling als aandeel van de eigen groep en gebruikt de volledige populatie van die groep als noemer.
Eén grote bestelling onder drie bestellingen uit East is ongeveer 33,3% van de bestellingen uit East, ongeacht de aantallen van andere regio's.

R

Rijvoorwaarde
Een rijvoorwaarde kan voor één invoerrecord worden geëvalueerd, bijvoorbeeld of de datum binnen een bereik ligt of het bedrag aan een grenswaarde voldoet.
De toets amount >= 60 kan de ene bestelling uit East behouden en een andere verwijderen voordat een regionale samenvatting bestaat.
ROUND
ROUND is een functie die een numerieke waarde afrondt, waarbij het tweede argument normaal het aantal cijfers achter de komma aangeeft.
ROUND(AVG(amount), 2) rondt het voltooide gemiddelde af op twee decimalen en laat de eerdere berekening intact.

S

SELECT-alias
Een SELECT-alias is een uitvoernaam die aan een expressie wordt toegekend en in ORDER BY kan worden gebruikt; het gebruik elders verschilt per dialect.
PostgreSQL accepteert ORDER BY total, maar vereist dat de aggregatie-expressie wordt uitgeschreven in een HAVING op hetzelfde niveau.
Sorteerregels (collation)
Sorteerregels zijn de regels die de database gebruikt om tekst te vergelijken en te ordenen, inclusief de invloed van hoofdletters en kleine letters op vergelijkingen.
Het minimum van tekstwaarden kan door de sorteerregels veranderen, ook wanneer de rijen en de MIN-query gelijk blijven.
SUM
SUM is een aggregatiefunctie die de numerieke waarden van een kolom of expressie die niet NULL zijn over de invoerrijen optelt.
SUM(quantity * unit_price) telt de omzetten per rij op nadat elk aantal met de bijbehorende prijs is vermenigvuldigd.

U

Unieke combinatie
Een unieke combinatie is een unieke verzameling waarden over geselecteerde kolommen die als één rij in een resultaat met unieke waarden wordt behandeld.
East/Ana en East/Dara zijn afzonderlijke paren wanneer een rapport unieke combinaties van regio en klant weergeeft.

V

Vergelijking zonder afronding
Een vergelijking zonder afronding toetst de oorspronkelijke berekende waarde, ook wanneer de geselecteerde uitvoer een afgeronde versie ervan toont.
Een gemiddelde dat als 86,67 wordt weergegeven, kan toch niet voldoen aan HAVING AVG(amount) >= 86.67 als de exacte waarde kleiner is.
Voorwaardelijk totaal
Een voorwaardelijk totaal telt de bedragen van rijen die voldoen op, meestal met een CASE-expressie die nul teruggeeft voor rijen die niet voldoen.
Een totaal van grote bestellingen geeft vanuit CASE het bedrag zelf terug dat voldoet; 1 teruggeven zou in plaats daarvan bestellingen tellen.
Voorwaardelijke aggregatie
Bij voorwaardelijke aggregatie hangt de bijdrage van elke rij af van een voorwaarde, zodat meerdere kengetallen voor deelverzamelingen in één rapport mogelijk zijn.
Een regionaal rapport kan alle bestellingen en grote bestellingen samen weergeven zonder eerst kleine bestellingen weg te filteren.
Voorwaardelijke telling
Een voorwaardelijke telling telt alleen rijen die aan een gekozen voorwaarde voldoen, vaak door rijen die niet voldoen binnen 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
Een waarde halverwege twee afrondingsuitkomsten ligt precies tussen twee mogelijke afgeronde resultaten; het gekozen resultaat hangt af van het getaltype en de afrondingsregel.
Exacte NUMERIC-afronding in PostgreSQL rondt 2,5 af naar 3 en -2,5 naar -3, beide van nul af.
WHERE
WHERE is de clausule die afzonderlijke invoerrijen vóór het groeperen filtert en bepaalt welke records bijdragen aan latere samenvattingen.
Een rapport dat is beperkt tot bestellingen uit 2026 gebruikt een datumvoorwaarde in 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.

Aan de slag