Cursus
WHERE en HAVING zijn twee essentiële clausules in SQL. Of je nu supergeavanceerde query’s of heel eenvoudige schrijft, je zult beide nodig hebben. Je kunt WHERE en HAVING zien als broer en zus: ze hebben een vergelijkbare functie (filteren) en komen vaak samen voor. Maar net als bij siblings hebben ze ook hun eigen kenmerken en rollen.
Als je trying-to-make-sense-of WHERE en HAVING bent, meld je dan aan voor onze skill track SQL Fundamentals als een sterk en compleet startpunt. Je leert er over de verschillende SQL-clausules, de volgorde van uitvoering in SQL, het optimaliseren van SQL-query’s en nog veel meer essentiële onderwerpen.
Het korte antwoord: WHERE vs. HAVING
Het korte antwoord, en de bron van verwarring voor veel mensen, is dat WHERE werkt op rijniveau-data, terwijl HAVING werkt op gegroepeerde data. Hierbij een richtlijn:
-
WHEREfiltert rijen vóórdat er grouping of aggregatie plaatsvindt. Het is van toepassing op individuele rijen en kan niet met aggregatiefuncties worden gebruikt. -
HAVINGfiltert groepen nadat de grouping en aggregatie zijn uitgevoerd. Het is van toepassing op de resultaten van aggregatiefuncties en wordt gebruikt in combinatie metGROUP BY.
Een snel voorbeeld om het verschil te laten zien
Laten we een snel voorbeeld bekijken. Wil je meedoen in je eigen workflow, download dan de dataset met huurwoningen uit deze GitHub-repository.
Stel nu dat we alle woningen in onze dataset willen teruggeven met een huurprijs van minder dan $500. Het detailniveau van elke rij in de dataset (één woning per rij) komt overeen met het detailniveau van de queryvoorwaarde. Daarom gebruiken we WHERE in de volgende query:
SELECT *
FROM rentals
WHERE rental_price < 500
Het resultaat ziet er zo uit. Let op dat er 118 rijen worden geretourneerd.

Eenvoudig rijen filteren met WHERE. Afbeelding door de auteur.
Stel nu dat we geen tabel met woningen willen, maar met steden die een gemiddelde huurprijs hebben van minder dan $2.700. In plaats van elke rij te laten overeenkomen met een woning, groeperen we de rijen en aggregeren we de huurprijs tot een gemiddelde huurprijs per stad. Daarom gebruiken we HAVING, zoals in deze query:
SELECT city, AVG(rental_price) AS average_rent
FROM rentals
GROUP BY city
HAVING AVG(rental_price) < 2700;
En het resultaat zou dit zijn. Let op: er is maar één resultaat.

Eenvoudig groepen filteren met HAVING. Afbeelding door de auteur.
WHERE, HAVING en de volgorde van uitvoering in SQL
We zien dat WHERE werkt met filteren op rijniveau, terwijl HAVING werkt met filteren op aggregatieniveau. Dit verschil begrijpen legt ook de basis om te leren over de volgorde waarin SQL-clausules worden uitgevoerd.
WHERE wordt geëvalueerd vóór GROUP BY, en direct na FROM (en JOIN als die aanwezig is); het kan niet omgaan met grouping of aggregatie. WHERE treedt in werking voordat er enige aggregatie is gedaan. Daarom werkt het alleen op rijniveau-data.
HAVING daarentegen komt pas na het uitvoeren van de GROUP BY-clausule. Dat betekent dat het pas wordt toegepast nadat de tabel is getransformeerd en gegroepeerd op een niveau dat verschilt van de granulariteit van de brontabel. HAVING werkt op de nieuwe, getransformeerde versie van de tabel.
De WHERE-clausule gebruiken in SQL
Laten we een stap terug doen en elke clausule afzonderlijk bekijken. We beginnen met de WHERE-clausule.
WHERE-syntax en -statements
WHERE kan worden gebruikt in drie verschillende SQL-statements: SELECT, UPDATE en DELETE.
WHERE in SELECT-statements
In SELECT-statements, die worden gebruikt om data uit de database op te halen, speelt WHERE zijn directe rol in filteren op rijniveau en staat het, zoals bekend, direct na de FROM-clausule, zoals we zien in de volgende query:
SELECT column1, column2… etc.
FROM table_name
WHERE condition;
WHERE gebruikt met SELECT is de plek waar de WHERE-clausule het vaakst wordt verward met HAVING.
WHERE in UPDATE-statements
Daarnaast speelt WHERE een belangrijke rol in UPDATE-statements om precies de rij aan te wijzen waar de data-update moet plaatsvinden, zoals we zien in de volgende syntax:
UPDATE table_name
SET column_name1 = value1, column_name2 = value2… etc.
WHERE condition;
WHERE in DELETE-statements
WHERE is ook een nuttige toevoeging aan DELETE-statements om de records (rijen) aan te wijzen die moeten worden verwijderd, zoals we hier zien:
DELETE FROM table_name
WHERE condition;
Hoe schrijf je WHERE-voorwaarden
WHERE-voorwaarden worden geschreven als een eenvoudige logische expressie. Die bestaat uit drie delen: de variabele/operand, de voorwaarde en de waarde/uitkomst. Laten we de opties voor WHERE-voorwaarden bekijken, met zowel vergelijkings- als logische operatoren.
| Operatorsymbool | Omschrijving | Datatype operand |
|---|---|---|
| = | Gelijk aan (op datum) | Numeriek, Tekst, Datum/timestamp, Boolean |
| < | Kleiner dan (vóór datum) | Numeriek, Datum/timestamp |
| > | Groter dan (na datum) | Numeriek, Datum/timestamp |
| <= | Kleiner dan of gelijk aan (op of vóór datum) | Numeriek, Datum/timestamp |
| >= | Groter dan of gelijk aan (op of na datum) | Numeriek, Datum/timestamp |
| <> (!=) | Niet gelijk aan (niet op datum) | Numeriek, Tekst, Datum/timestamp, Boolean |
| IN | Gelijk aan meer dan één waarde (op meerdere data) | Numeriek, Tekst, Datum/timestamp, Boolean (wel onzinnig!) |
| LIKE | Komt overeen met tekstpatroon (met wildcards) | Tekst |
| BETWEEN | Ligt binnen een bereik | Numeriek, Datum/timestamp |
| AND | Combineert meerdere voorwaarden, allemaal moeten waar zijn | Logisch (Boolean) |
| OR | Combineert meerdere voorwaarden, minstens één moet waar zijn | Logisch (Boolean) |
| NOT | Keert een voorwaarde om | Logisch (Boolean) |
| IS NULL | Controleert op null-waarden | Alle datatypen |
| IS NOT NULL | Controleert op niet-null-waarden | Alle datatypen |
Hier is een voorbeeld waarin we NOT gebruiken samen met de vergelijkingsoperator IN:
SELECT *
FROM rentals
WHERE city NOT IN ('Cairo', 'Giza');
De statement retourneert alle woningen die noch in de stad Cairo noch in Giza liggen.

Woningen buiten Cairo en Giza. Afbeelding door de auteur.
Gebruikssituaties voor WHERE
Omdat WHERE werkt met SELECT-, UPDATE- en DELETE-statements, kun je drie use-cases voorzien: filteren op rijniveau, data-opvraging en datamanipulatie.
Filteren op rijniveau
We kunnen rijen in onze tabel filteren op basis van één of meer voorwaarden. De volgende query filtert rijen zodat alleen villa’s worden opgenomen.
SELECT *
FROM rentals
WHERE type = ‘villa’;

Villa’s selecteren. Afbeelding door de auteur.
Data-opvraging
WHERE kan worden gebruikt om een specifiek datapunt op te halen waar we naar op zoek zijn. Dit lijkt op filteren op rijniveau maar is specifieker. Stel dat we de ID willen weten van de woning die op 1 januari 2022 in Cairo beschikbaar was, dan kunnen we de volgende query gebruiken:
SELECT property_id
FROM rentals
WHERE available_date = '2022-01-01'
AND city = 'Cairo';

Een datapunt ophalen. Afbeelding door de auteur.
Datamanipulatie
Tot slot is WHERE erg handig om waarden te wijzigen en specifieke records in je database te verwijderen. Stel bijvoorbeeld dat we ontdekten dat woning 171 eigenlijk niet huisdiervriendelijk is; dan kunnen we de kolom pet_friendly aanpassen met WHERE in een UPDATE-statement als volgt:
UPDATE rentals
SET pet_friendly = false
WHERE property_id = 171;
De HAVING-clausule gebruiken in SQL
Nu is het tijd om met dezelfde diepgang naar de HAVING-clausule te kijken.
HAVING-syntax en -statements
Allereerst moeten we weten dat de HAVING-clausule alleen kan worden gebruikt in SELECT-statements. De enige mogelijke syntax is daarom als volgt:
SELECT grouped_column, aggregate_function(aggregated_column)… etc.
FROM table_name
GROUP BY grouped_column
HAVING condition
Let op: je kunt meer dan één gegroepeerde kolom en meer dan één geaggregeerde kolom toevoegen. Hieronder zien we voorbeelden.
Hoe schrijf je HAVING-voorwaarden
Net als WHERE worden HAVING-voorwaarden geschreven als logische expressies, maar met één extra component: de aggregatiefunctie. Een HAVING-voorwaarde bestaat dus uit 1) Aggregatiefunctie, 2) variabele/operand, 3) vergelijkingsoperator en 4) waarde/uitkomst.
Aggregatiefuncties met HAVING
SQL heeft in hoofdzaak vijf aggregatiefuncties, plus een zesde in een bijzonder geval. Deze functies zijn:
| Aggregatiefunctie | Geschikt datatype |
|---|---|
| SUM() | Numeriek |
| AVG() | Numeriek |
| MIN() | Numeriek, Tekst, Datum/timestamp |
| MAX() | Numeriek, Tekst, Datum/timestamp |
| COUNT() | Numeriek, Tekst, Datum/timestamp, Boolean |
Laten we een voorbeeld proberen. Hier gebruiken we de functie COUNT() met GROUP BY om een frequentietabel te maken, en gebruiken we de HAVING-voorwaarde als filter. Concreet willen we de steden weten die 150 keer of minder voorkomen, wat in deze context te maken heeft met het aantal registraties. We kunnen deze query gebruiken:
SELECT city, COUNT(*) AS properties_count
FROM rentals
GROUP BY city
HAVING COUNT(*) <= 150;

COUNT() gebruiken met HAVING. Afbeelding door de auteur.
Vergelijkings- en logische operatoren
HAVING accepteert alle vergelijkings- en logische operatoren die WHERE accepteert. Het enige verschil is dat het geschikte datatype bij HAVING in de eerste plaats afhangt van de aggregatiefunctie, zoals we in de tabel hierboven zien.
Gebruikssituaties voor HAVING
In tegenstelling tot WHERE kan HAVING niet worden gebruikt in UPDATE- en DELETE-statements; HAVING wordt alleen gebruikt voor data-opvraging. Grofweg vertaalt dit zich naar twee scenario’s:
Filteren op groepsniveau
Dit is het gebruikelijke en normale gebruik van HAVING. Een voorbeeld is alleen die steden teruggeven met gemiddelde huurprijzen onder $2.700.
SELECT city, AVG(rental_price) AS avg_price
FROM rentals
GROUP BY city
HAVING AVG(rental_price) < 2700;
Filteren tot één rij
Dit is een ongebruikelijk geval, maar HAVING kan worden gebruikt om een aggregatie met één rij, zoals een metric of KPI, terug te geven, maar alleen als die aan een bepaalde voorwaarde voldoet. Dit kan worden bereikt door HAVING te gebruiken zonder GROUP BY. In het volgende voorbeeld retourneren we de gemiddelde huurprijs alleen als die lager is dan $2.800. Als de maatregel aan de voorwaarde voldoet, krijgen we een resultaat met één rij. Zo niet, dan krijgen we een lege tabel.
SELECT AVG(rental_price) as avg_price
FROM rentals
HAVING AVG(rental_price) > 2800;
WHERE en HAVING combineren
WHERE en HAVING kunnen worden gecombineerd om tabellen te filteren vóór en na aggregatie. In het volgende voorbeeld geven we het aantal woningen per stad terug, waarbij we alleen woningen meetellen die huisdiervriendelijk zijn, en filteren we naar alleen steden met meer dan 80 woningen.
SELECT city, COUNT(*) AS number_properties
FROM rentals
WHERE pet_friendly = true
GROUP BY city
HAVING COUNT(*) > 80;

Basale combinatie van WHERE en HAVING. Afbeelding door de auteur.
Het verschil tussen WHERE en HAVING qua performance
We weten dat de WHERE-clausule wordt toegepast vóór grouping of aggregatie. Om die reden is WHERE efficiënter voor het filteren van individuele rijen, omdat het vroeg in de query het aantal te verwerken rijen vermindert.
We weten aan de andere kant dat de HAVING-clausule wordt toegepast ná aggregatie en het resultaat filtert op basis van gegroepeerde data. Omdat dit gebeurt nadat alle rijen zijn gegroepeerd, is het over het algemeen minder efficiënt dan WHERE, al is het wel noodzakelijk voor voorwaarden die aggregatiefuncties omvatten.
Laten we naar deze query kijken:
SELECT city, COUNT(*)
FROM rentals
GROUP BY city
HAVING rental_price < 2700;
Deze query is inefficiënt omdat de voorwaarde rental_price niet afhankelijk is van een aggregatie — het filtert individuele rijen. Deze query zal eerst alle verhuurobjecten per stad groeperen, ze tellen en dán het resultaat filteren, wat inefficiënt is omdat er onnodige rijen worden verwerkt. Daarom zou dit een snellere query zijn geweest:
SELECT city, COUNT(*)
FROM rentals
WHERE rental_price < 2700
GROUP BY city;
Optimalisatietips voor WHERE en HAVING
Op basis van het voorgaande zien we enkele goede praktijken om ons gebruik van de clausules WHERE en HAVING te optimaliseren. Dit is belangrijk bij grote datasets.
-
Wees heel selectief: Filter precies op de waarden waarop je moet filteren en niet meer. Dit helpt het aantal rijen in de view te verminderen en verhoogt zo de efficiëntie van de query.
-
Houd het simpel: Haal onnodige voorwaarden, aggregaties en typecasts weg. Al deze extra’s hebben zeker een rekentechnische prijs.
-
Filter vroeg: Als je een aggregatie op groepsniveau doet, prefilter de rijen met
WHEREom het groeperingsproces te versnellen. Zo verlaag je het aantal rijen dat in de grouping verwerkt moet worden.
Vergelijkingstabel
Laten we onze gedachten samenvatten in een handige tabel:
| Vergelijking | WHERE | HAVING |
|---|---|---|
| Hoofddoel | Filteren op rijniveau | Filteren op groepsniveau |
| Basissyntax | SELECT column1, column2... FROM table_name WHERE condition; | SELECT grouped_column, aggregate_function(aggregated_column)... FROM table_name GROUP BY grouped_column HAVING condition; |
| Volgorde van evaluatie | Voor GROUP BY | Na GROUP BY |
| Compatibele statements | SELECT, UPDATE, DELETE | SELECT |
| Voorwaarden | Kunnen geen aggregatiefuncties bevatten | Moeten aggregatiefuncties bevatten |
| Use-cases | Filteren op rijniveau Data-opvraging Datamanipulatie | Filteren op groepsniveau Filteren tot één rij |
| Subquery’s | Kan werken met subquery’s | Moeten als CTE’s worden geschreven |
Conclusie
In dit artikel hebben we het belangrijkste verschil tussen WHERE en HAVING in SQL verkend: de WHERE-clausule filtert rijen vóór aggregatie, terwijl de HAVING-clausule gegroepeerde data filtert ná aggregatie. We hebben ook enkele minder bekende verschillen besproken, zoals het feit dat WHERE kan werken met SELECT-, UPDATE- en DELETE-statements, terwijl HAVING alleen werkt met SELECT. Ook hebben we kort over performance gesproken.
De SQL Basics Cheat Sheet van DataCamp geeft een fijne samenvatting van de clausules WHERE en HAVING, en wat houvast bij het filteren in SQL. Als je net begint met SQL, kijk dan zeker ook naar de skill track SQL Fundamentals en de career track Associate Data Analyst in SQL.

Islam is data consultant bij The KPI Institute. Met een achtergrond in de journalistiek heeft Islam brede interesses, waaronder schrijven, filosofie, media, technologie en cultuur.
Veelgestelde vragen
Wat is het verschil tussen WHERE en HAVING?
WHERE filtert op rijniveau, terwijl HAVING op groepsniveau filtert.
Kan ik WHERE en HAVING in één query combineren?
Ja, en het is sterk aan te raden om WHERE te gebruiken als je HAVING gaat gebruiken.
Kan WHERE werken met aggregatiefuncties zoals HAVING?
Nee, alleen HAVING kan werken met aggregatiefuncties.
Werken WHERE en HAVING met dezelfde vergelijkings- en logische operatoren?
Ja, ze werken allebei met dezelfde operatoren, omdat WHERE- en HAVING-voorwaarden worden geschreven als logische expressies.
Kan ik HAVING gebruiken zonder GROUP BY?
HAVING wordt meestal gebruikt na groeperen met GROUP BY. De enige uitzondering hierop is filteren van een weergave met één waarde (zoals het berekenen van één metric).
