Direct naar de hoofdinhoud
Module 3 · Les 4 van 412/57 in de cursus~8 min
Modulelessen (4/4)

Groepen filteren: HAVING

Als je eenmaal een resultaat per groep hebt (vorige les), wil je dat vaak ook alleen de groepen behouden die aan een voorwaarde voldoen: afdelingen met meer dan 2 personen, projecten met een gemiddeld budget boven de 100.000, gebruikers met minimaal 10 bestellingen. Om dit te doen is WHERE niet genoeg.

Waarom WAAR niet genoeg is

WHERE filtert de tabelrijen, vóór aggregatie. Dus het kan niet zien het resultaat van COUNT(*) of AVG(...): tegen de tijd dat WHERE wordt uitgevoerd, zijn deze waarden zijn nog niet berekend.

SQL
-- ERROR: COUNT(*) doesn't exist yet when WHERE is evaluated
SELECT department_id, COUNT(*) AS count
FROM   employees
WHERE  COUNT(*) > 2     -- ❌ doesn't work
GROUP BY department_id;

Om na aggregatie te filteren, is er een speciale clausule: HAVING.

De syntaxis

SQL
SELECT grouping_column, AGGREGATE_FUNCTION(...)
FROM   table
GROUP BY grouping_column
HAVING   condition_on_aggregate;
SQL
-- Departments with more than 2 employees:
SELECT department_id, COUNT(*) AS count
FROM   employees
GROUP BY department_id
HAVING   COUNT(*) > 2;

HAVING is voor GROUP BY wat WHERE is voor FROM: hetzelfde idee ("filter"), maar na groepering toegepast op het aggregaat.

De logische volgorde van clausules

Om WHERE en HAVING nooit meer te verwarren, onthoud de volgorde waarin SQL voert ze mentaal uit:

  1. FROM / JOIN — bouwt de starttabel op door bronnen samen te voegen.
  2. WHERE — verwijdert de rijen die u niet interesseren.
  3. GROUP BY — verzamelt de resterende rijen in groepen.
  4. HAVING — verwijdert de groepen die je niet interesseren.
  5. SELECT — berekent de laatste kolommen (inclusief aggregaten).
  6. ORDER BY / LIMIT — opnieuw ordenen en knippen.

Belangrijke opmerkingen:

  • in WHERE kun je alleen tabelkolommen gebruiken;
  • in HAVING kunt u kolommen en aggregaties groeperen gebruiken.
SQL
-- Classic combo: filter first, group, filter the groups, sort.
SELECT d.name, AVG(e.salary) AS average
FROM   employees   AS e
JOIN   departments AS d ON e.department_id = d.id
WHERE  e.hired_on >= '2018-01-01'   -- filter rows
GROUP BY d.name
HAVING   AVG(e.salary) > 35000      -- filter groups
ORDER BY average DESC;

Probeer het

Oefening#sql.m3.l4.e1
Pogingen: 0Laden…

Toon voor elke afdeling de naam (departments.name) en het aantal medewerkers, MAAR alleen voor afdelingen met minimaal 2 medewerkers. Twee kolommen, één rij per kwalificerende afdeling.

Editor laden…
Toon hint

De voorwaarde 'minstens 2' wordt COUNT(*) >= 2 in HAVING.

Oplossing beschikbaar na 3 pogingen

Oefening beoordelen

Oefening#sql.m3.l4.e2
Pogingen: 0Laden…

Toon de afdelingen (departments.name) waarvan het gemiddelde salaris hoger is dan 35.000. Beschouw alleen werknemers die vanaf 2018 zijn aangenomen. Twee kolommen: naam en het gemiddelde. Sorteer op gemiddeld aflopend.

Editor laden…
Toon hint

WHERE filtert de rijen (medewerkers ingehuurd vanaf 2018), HAVING filtert de groepen (gemiddeld > 35000).

Oplossing beschikbaar na 3 pogingen