Leçons du module (4/4)
Filtrer les groupes : HAVING
Une fois que vous avez un résultat par groupe (cours précédent), vous avez souvent envie de
ne conserver que les groupes qui satisfont à une condition : départements avec plus
plus de 2 personnes, projets avec un budget moyen supérieur à 100k, utilisateurs avec
au moins 10 commandes. Pour ce faire, WHERE ne suffit pas.
Pourquoi OÙ ne suffit pas
WHERE filtre les lignes du tableau, avant l'agrégation. Donc ça ne peut pas voir
le résultat de COUNT(*) ou AVG(...) : au moment où WHERE s'exécute, ceux-ci
les valeurs n'ont pas encore été calculées.
-- 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;Pour filtrer après l'agrégation, il existe une clause dédiée : HAVING.
La syntaxe
SELECT grouping_column, AGGREGATE_FUNCTION(...)
FROM table
GROUP BY grouping_column
HAVING condition_on_aggregate;-- Departments with more than 2 employees:
SELECT department_id, COUNT(*) AS count
FROM employees
GROUP BY department_id
HAVING COUNT(*) > 2;HAVING est à GROUP BY ce que WHERE est à FROM : la même idée
("filtre"), mais appliqué après le regroupement, sur l'ensemble.
L'ordre logique des clauses
Pour ne plus jamais confondre WHERE et HAVING, rappelez-vous l'ordre dans lequel
SQL les exécute mentalement :
FROM/JOIN— construit la table de départ en joignant les sources.WHERE— supprime les lignes qui ne vous intéressent pas.GROUP BY— collecte les lignes restantes en groupes.HAVING— supprime les groupes qui ne vous intéressent pas.SELECT— calcule les colonnes finales (y compris les agrégats).ORDER BY/LIMIT— réorganiser et couper.
Remarques importantes :
- dans
WHEREvous ne pouvez utiliser que des colonnes de tableau ; - dans
HAVING, vous pouvez utiliser le regroupement de colonnes et d'agrégats.
-- 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;Essayez-le
Pour chaque département, affichez le nom (departments.name) et le nombre d'employés, MAIS uniquement pour les départements comptant au moins 2 employés. Deux colonnes, une ligne par département éligible.
Afficher l'indice
La condition 'au moins 2' devient COUNT(*) >= 2 dans HAVING.
Solution disponible après 3 tentatives
Exercice de révision
Affichez les départements (departments.name) dont le salaire moyen dépasse 35 000. Ne considérez que les employés embauchés à partir de 2018. Deux colonnes : le nom et la moyenne. Trier par moyenne décroissante.
Afficher l'indice
WHERE filtre les lignes (employés embauchés à partir de 2018), HAVING filtre les groupes (moyenne > 35000).
Solution disponible après 3 tentatives