WHERE ou HAVING en SQL : filtrer les lignes et les groupes
WHERE filtre les lignes individuelles avant le regroupement. HAVING filtre les groupes après l’agrégation. Combinez les deux si un rapport impose une condition sur chaque transaction et une autre sur les totaux.
« Les régions ayant au moins 150 de ventes payées » contient deux règles : seules les transactions payées contribuent et seules les régions dont le total atteint 150 sont affichées. Placer les deux conditions au même endroit peut changer le sens ou rendre la requête invalide.
| Condition | Clause |
|---|---|
| Conserver les transactions payées | WHERE status = ‘paid’ |
| Garder les groupes avec un total d’au moins 150 | HAVING SUM(amount) >= 150 |
| Trier les groupes finaux | ORDER BY |
Raisonnez avec les étapes logiques FROM, WHERE, GROUP BY, HAVING, SELECT, ORDER BY. Elles aident à comprendre la requête, sans imposer l’ordre physique choisi par l’optimiseur.
Essayez dans SQLite
Ouvrez SQL Lab, collez cette préparation et exécutez-la une fois. Lancez ensuite chaque requête séparément. Les noms des tables et des colonnes restent en anglais pour utiliser le même SQL dans toutes les langues. Le laboratoire et les leçons liées sont actuellement en anglais.
CREATE TABLE blog_sales (
id INTEGER PRIMARY KEY, region TEXT, status TEXT, amount INTEGER
);
INSERT INTO blog_sales VALUES
(1, 'North', 'paid', 100), (2, 'North', 'paid', 80),
(3, 'North', 'refunded', 500), (4, 'South', 'paid', 70),
(5, 'South', 'paid', 90), (6, 'West', 'paid', 40);
1. Combiner les filtres de lignes et de groupes
North totalise 180 de ventes payées, pas 680 : la transaction remboursée ne doit pas contribuer. South totalise 160 et West 40. WHERE retire le remboursement avant le regroupement ; HAVING retire ensuite West.
SELECT region, SUM(amount) AS paid_total, COUNT(*) AS paid_orders
FROM blog_sales
WHERE status = 'paid'
GROUP BY region
HAVING SUM(amount) >= 150
ORDER BY region;
Résultat attendu
| region | paid_total | paid_orders |
|---|---|---|
| North | 180 | 2 |
| South | 160 | 2 |
2. Un seuil sur les lignes retire des transactions
Ajouter amount >= 80 dans WHERE élimine la transaction payée de 70 pour South. Son total devient 90. On calcule alors le total des grosses transactions individuelles, plutôt que les régions ayant de gros totaux.
SELECT region, SUM(amount) AS total
FROM blog_sales
WHERE status = 'paid' AND amount >= 80
GROUP BY region
ORDER BY region;
Résultat attendu
| region | total |
|---|---|
| North | 180 |
| South | 90 |
3. Un seuil sur les groupes conserve les contributions
Avec la condition dans HAVING, les deux transactions payées de South contribuent au total, qui reste 160. West est exclu parce que son total est inférieur à 80. Des conditions semblables peuvent répondre à des questions métier différentes.
SELECT region, SUM(amount) AS total
FROM blog_sales
WHERE status = 'paid'
GROUP BY region
HAVING SUM(amount) >= 80
ORDER BY region;
Résultat attendu
| region | total |
|---|---|
| North | 180 |
| South | 160 |
Exercice et vérification
Affichez les régions ayant au moins deux transactions payées. Gardez WHERE status = 'paid', regroupez par region et utilisez HAVING COUNT(*) >= 2. Le résultat contient North et South, avec deux transactions chacune.
Pour déboguer, examinez les lignes conservées par WHERE, exécutez le regroupement sans HAVING, puis ajoutez le filtre des groupes. Vous verrez si les données manquantes viennent du filtre de lignes ou du seuil appliqué au total.
Ne placez pas SUM(amount) dans WHERE pour cette requête regroupée : le total n’est pas encore disponible. Ne sélectionnez pas non plus une colonne comme id si elle n’est ni regroupée ni agrégée. Les moteurs stricts refusent cette requête ; les moteurs permissifs peuvent retourner une valeur qui ne représente pas le groupe.
Pour une meilleure portabilité, utilisez l’expression agrégée dans HAVING plutôt que son alias SELECT. HAVING ne remplace pas tous les filtres WHERE. Une condition portant sur chaque ligne d’entrée appartient généralement à WHERE, sauf si vous recherchez volontairement une autre signification au niveau des groupes.
Documentation et suite du parcours
Poursuivez avec la leçon GROUP BY et HAVING. Les exemples fonctionnent dans SQLite. La distinction lignes/groupes s’applique aux bases relationnelles courantes, mais les règles d’alias et de regroupement diffèrent selon le moteur.
Essayez les exemples dans SQL Lab
Copiez la préparation et les requêtes de ce guide dans le laboratoire. Les exemples utilisent SQLite. Les leçons et les consignes du laboratoire sont en anglais.
Ouvrir SQL Lab