Filtrer les groupes avec HAVING
Leçon 4.3 · Temps de lecture: ~7 minutes · Exercices pratiques ↓
Quand vous utilisez GROUP BY avec les agrégations, vous devez souvent filtrer les groupes par leurs résultats agrégés. HAVING est l'opérateur pour filtrer les groupes, comme WHERE filtre les lignes individuelles. Dans cette leçon, vous apprendrez les différences entre WHERE et HAVING, la syntaxe et des exemples pratiques sur Sakila. À la fin, vous utiliserez HAVING avec assurance pour l'analyse approfondie des données.
Dans les leçons précédentes, vous avez appris GROUP BY pour grouper les données et appliquer les agrégations. Vient maintenant l'étape suivante: filtrer les groupes eux-mêmes par des conditions sur les valeurs agrégées.
HAVING fait cela en permettant des conditions après le regroupement.
100 garde 395 clients sur 599" width="100%">
WHERE vs HAVING
- WHERE filtre les lignes avant le regroupement
- HAVING filtre les groupes après l'agrégation
SELECT colonne1, COUNT(*) AS cnt
FROM table
WHERE colonne1 > 100 -- filtrer AVANT le regroupement
GROUP BY colonne1
HAVING COUNT(*) > 10; -- filtrer APRÈS le regroupement
Syntaxe de HAVING
Structure de base:
SELECT colonne1, FONCTION_AGG(colonne2)
FROM table
GROUP BY colonne1
HAVING condition;
La condition en HAVING implique généralement une fonction d'agrégation.
Exemples avec une seule condition
Clients avec paiements totaux au-dessus de 100
SELECT customer_id, SUM(amount) AS total_paye
FROM payment
GROUP BY customer_id
HAVING SUM(amount) > 100;
Résultat: uniquement les clients dont les paiements totaux dépassent 100.
Employés ayant traité plus de 50 paiements
SELECT staff_id, COUNT(*) AS nb_paiements
FROM payment
GROUP BY staff_id
HAVING COUNT(*) > 50;
Résultat: employés avec plus de 50 paiements traités.
Clients avec paiement moyen >= 5
SELECT customer_id, AVG(amount) AS paiement_moyen
FROM payment
GROUP BY customer_id
HAVING AVG(amount) >= 5;
Résultat: clients dont le paiement moyen est d'au moins 5.
HAVING avec plusieurs conditions
Vous pouvez combiner les conditions avec AND et OR:
SELECT staff_id, COUNT(*) AS cnt, SUM(amount) AS total
FROM payment
GROUP BY staff_id
HAVING COUNT(*) > 50 AND SUM(amount) > 500;
Résultat: employés avec plus de 50 paiements ET total au-dessus de 500.
Avec l'opérateur OR
SELECT customer_id, COUNT(*) AS rentals, SUM(amount) AS paid
FROM payment
GROUP BY customer_id
HAVING COUNT(*) > 100 OR SUM(amount) > 1000;
Résultat: clients avec plus de 100 paiements OU total au-dessus de 1000.
Exemples pratiques
Catégories de films avec ventes au-dessus de 2000
SELECT category_id, SUM(p.amount) AS total_ventes
FROM payment p
JOIN rental r ON p.rental_id = r.rental_id
JOIN inventory i ON r.inventory_id = i.inventory_id
JOIN film_category fc ON i.film_id = fc.film_id
GROUP BY category_id
HAVING SUM(p.amount) > 2000;
Pays avec plus de 20 clients
SELECT country, COUNT(*) AS nb_clients
FROM customer cu
JOIN address a ON cu.address_id = a.address_id
JOIN city ci ON a.city_id = ci.city_id
JOIN country co ON ci.country_id = co.country_id
GROUP BY country
HAVING COUNT(*) > 20;
Employés avec un chiffre d'affaires quotidien supérieur à 500
SELECT staff_id, DATE(payment_date) AS date_paiement, SUM(amount) AS revenus_quotidiens
FROM payment
GROUP BY staff_id, DATE(payment_date)
HAVING SUM(amount) > 500;
Résultat : 56 lignes, chaque paire employé-jour où l'employé a encaissé plus de 500.
Questions fréquentes
Pourquoi ne puis-je pas utiliser WHERE au lieu de HAVING?
WHERE fonctionne avant le regroupement, il ne peut donc pas vérifier les fonctions d'agrégation. HAVING fonctionne après le regroupement et peut analyser les résultats d'agrégation (COUNT, SUM, AVG, etc.).
Puis-je utiliser une colonne non agrégée dans HAVING?
Oui, vous pouvez utiliser une colonne de GROUP BY, mais cela n'est généralement pas nécessaire. Par exemple, HAVING customer_id > 100 fonctionne, mais il est plus naturel d'écrire cela dans WHERE avant le regroupement.
HAVING peut-il être utilisé sans GROUP BY?
Techniquement dans certains SGBD c'est possible, mais c'est peu pratique car HAVING est conçu pour filtrer les groupes. Utilisez WHERE pour filtrer les lignes individuelles sans regroupement.
Questions d'entretien
Qu'est-ce que HAVING et en quoi diffère-t-il de WHERE?
HAVING filtre les groupes après agrégation, tandis que WHERE filtre les lignes avant regroupement. WHERE ne peut pas fonctionner avec les fonctions d'agrégation, mais HAVING fonctionne uniquement avec elles.
Puis-je utiliser WHERE et HAVING ensemble dans une requête?
Oui, c'est même recommandé. WHERE filtre les lignes avant regroupement et HAVING filtre les groupes après. Par exemple, WHERE amount > 10 GROUP BY customer_id HAVING SUM(amount) > 100 exclut d'abord les petits paiements, puis regroupe et filtre les groupes.
Quel est l'ordre d'exécution: WHERE ou HAVING?
WHERE est appliqué en premier (avant GROUP BY), puis GROUP BY effectue le regroupement, puis HAVING filtre les groupes résultants, et enfin ORDER BY et LIMIT sont appliqués.
Points clés de cette leçon:
- HAVING filtre les groupes après agrégation, WHERE filtre les lignes avant regroupement.
- HAVING est utilisé avec les fonctions d'agrégation (COUNT, SUM, AVG, MIN, MAX).
- Vous pouvez combiner plusieurs conditions dans HAVING en utilisant AND/OR.
- Souvent WHERE et HAVING fonctionnent ensemble: WHERE exclut les lignes inutiles, HAVING filtre les groupes.
- HAVING permet des requêtes analytiques profondes avec filtrage au niveau du groupe.