SQL Pratique
HAVING vs WHERE en SQL : filtrer comme un expert
8 min de lecture

HAVING vs WHERE en SQL : filtrer comme un expert

Comprenez la différence entre WHERE et HAVING en SQL, quand utiliser chacun et comment éviter les erreurs classiques en entretien. Exemples inclus.

Avatar de Thomas LeroyThomas Leroy

La différence entre WHERE et HAVING est l'une des questions les plus fréquentes en entretien SQL — et l'une des plus mal comprises. En une phrase : WHERE filtre les lignes avant le regroupement, HAVING filtre les groupes après. Cette distinction semble simple, mais elle cache des subtilités qui peuvent faire la différence entre une requête correcte et une requête silencieusement fausse.

Dans cet article, vous allez maîtriser ces deux clauses de fond en comble : syntaxe, ordre d'exécution, cas d'usage réels et pièges à éviter. Que vous prépariez un entretien technique ou que vous cherchiez à écrire des requêtes plus propres, ce guide vous donne les bases et les réflexes qu'il faut.

📌 Ce qu'il faut retenir

  • WHERE s'applique sur les lignes brutes, avant GROUP BY
  • HAVING s'applique sur les groupes, après GROUP BY
  • On ne peut pas utiliser d'alias de colonne agrégée dans WHERE
  • HAVING sans GROUP BY existe mais reste rare et déroutant
  • L'ordre d'exécution SQL est : FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY

L'ordre d'exécution SQL, fondement de tout

Avant d'opposer WHERE et HAVING, il faut comprendre dans quel ordre le moteur SQL exécute une requête. L'ordre d'écriture et l'ordre d'exécution sont différents, et c'est là que la confusion naît.

Voici l'ordre logique d'exécution d'une requête SQL standard :

  1. FROM / JOIN — identification des tables sources
  2. WHERE — filtrage des lignes
  3. GROUP BY — regroupement
  4. HAVING — filtrage des groupes
  5. SELECT — projection des colonnes
  6. ORDER BY — tri final

Ce séquencement explique pourquoi vous ne pouvez pas référencer un alias défini dans SELECT à l'intérieur d'un WHERE : au moment où WHERE est évalué, SELECT n'a pas encore été exécuté. De même, vous ne pouvez pas filtrer sur COUNT(*) dans un WHERE, car le comptage n'existe qu'après le GROUP BY.

Gardez cette séquence en tête — elle répond à 90 % des questions sur WHERE vs HAVING.

WHERE : filtrer avant le regroupement

WHERE est la clause de filtrage la plus fondamentale de SQL. Elle agit sur chaque ligne de la table source, avant toute agrégation.

SELECT
  pays,
  COUNT(*) AS nb_commandes
FROM commandes
WHERE statut = 'livree'
GROUP BY pays;

Dans cet exemple, seules les commandes avec statut = 'livree' entrent dans le calcul. Les commandes annulées ou en attente sont écartées avant que le moteur ne commence à compter. Le résultat est donc le nombre de commandes livrées par pays.

WHERE accepte n'importe quelle condition sur les colonnes brutes : comparaisons, LIKE, IN, BETWEEN, sous-requêtes corrélées ou non. Pour en savoir plus sur les sous-requêtes dans ce contexte, consultez notre article sur les sous-requêtes SQL corrélées et imbriquées.

⚠️ Attention

Vous ne pouvez pas écrire WHERE COUNT(*) > 5. Cette syntaxe est invalide car COUNT n'est pas encore calculé à ce stade. Utilisez HAVING pour ce type de filtre.

HAVING : filtrer après le regroupement

HAVING a été introduit précisément pour pallier l'impossibilité d'utiliser des fonctions d'agrégat dans WHERE. Il s'applique après que les groupes ont été constitués et les agrégations calculées.

SELECT
  pays,
  COUNT(*) AS nb_commandes
FROM commandes
WHERE statut = 'livree'
GROUP BY pays
HAVING COUNT(*) > 100;

Ici, on conserve uniquement les pays ayant plus de 100 commandes livrées. Les deux clauses coexistent : WHERE réduit le périmètre des données à analyser, HAVING filtre les résultats agrégés.

HAVING peut utiliser :

  • des fonctions d'agrégat : COUNT(), SUM(), AVG(), MIN(), MAX()
  • des colonnes du GROUP BY
  • des sous-requêtes scalaires

Pour maîtriser les fonctions d'agrégat utilisées dans HAVING, notre guide sur les fonctions d'agrégat SQL détaille chaque fonction avec des exemples pratiques.

Tableau comparatif : WHERE vs HAVING

Critère WHERE HAVING
Moment d'exécution Avant GROUP BY Après GROUP BY
Agit sur Lignes individuelles Groupes agrégés
Fonctions d'agrégat autorisées Non Oui
Utilisation sans GROUP BY Oui (filtre classique) Possible, mais rare
Impact sur la performance Réduit les lignes tôt → plus rapide Agit sur données déjà agrégées
Alias SELECT accepté Non (dans la plupart des SGBD) Parfois (MySQL, BigQuery)
Exemple typique WHERE date > '2025-01-01' HAVING SUM(montant) > 1000

Combiner WHERE et HAVING intelligemment

La puissance réelle apparaît quand les deux clauses travaillent ensemble. Voici un cas concret : identifier les vendeurs actifs depuis 2024 dont le chiffre d'affaires total dépasse 50 000 €.

SELECT
  vendeur_id,
  SUM(montant) AS ca_total
FROM ventes
WHERE date_vente >= '2024-01-01'   -- filtre les lignes récentes
GROUP BY vendeur_id
HAVING SUM(montant) > 50000;       -- filtre sur l'agrégat

Mettre date_vente >= '2024-01-01' dans WHERE plutôt que dans HAVING est crucial pour la performance : le moteur écarte d'emblée toutes les ventes antérieures à 2024, réduisant le volume de données à agréger. Si vous placiez cette condition dans HAVING, toutes les ventes historiques seraient d'abord chargées en mémoire pour être ensuite rejetées — un gaspillage coûteux sur de grands volumes.

💡 Bon à savoir

En règle générale, placez dans WHERE tout ce qui ne nécessite pas d'agrégation. Cela réduit le volume de données traité par GROUP BY et améliore significativement les performances sur de grandes tables.

Cas avancés et pièges en entretien

HAVING sans GROUP BY

Il est techniquement possible d'utiliser HAVING sans GROUP BY. Dans ce cas, toute la table est traitée comme un seul groupe.

SELECT SUM(montant) AS total
FROM ventes
HAVING SUM(montant) > 100000;

Cette requête retourne le total global si celui-ci dépasse 100 000, sinon elle ne retourne rien. C'est légal, mais peu lisible. En entretien, si on vous demande si HAVING nécessite GROUP BY, la réponse est non — mais mentionnez que c'est un cas marginal.

Les alias dans HAVING

La gestion des alias varie selon le SGBD :

  • PostgreSQL / SQL Server / Oracle : alias non reconnus dans HAVING, il faut répéter l'expression agrégée
  • MySQL / BigQuery : acceptent parfois les alias dans HAVING

En entretien, évitez de supposer que les alias fonctionnent dans HAVING — répéter la fonction d'agrégat est toujours la solution la plus portable :

-- Portable et sûr
HAVING SUM(montant) > 50000

-- Risqué selon le SGBD
HAVING ca_total > 50000

Filtrer sur plusieurs agrégats

HAVING accepte plusieurs conditions combinées avec AND / OR :

SELECT
  categorie,
  COUNT(*) AS nb_produits,
  AVG(prix) AS prix_moyen
FROM produits
GROUP BY categorie
HAVING COUNT(*) >= 10
   AND AVG(prix) BETWEEN 20 AND 200;

Cette requête cible les catégories avec au moins 10 produits et un prix moyen compris entre 20 et 200 €. C'est un type de requête très apprécié en entretien pour tester la maîtrise des agrégats combinés.

Erreurs classiques à éviter

Voici les 3 erreurs les plus fréquentes observées en entretien et en code de production :

  • Utiliser WHERE avec une fonction d'agrégat : WHERE SUM(montant) > 100 génère une erreur syntax ou sémantique selon le SGBD
  • Dupliquer un filtre en HAVING alors qu'il devrait être en WHERE : perte de performance inutile sur les grandes tables
  • Oublier que HAVING sans GROUP BY traite toute la table comme un groupe unique — comportement souvent inattendu

Avec la montée en puissance des outils d'IA pour générer du SQL, il devient également crucial de savoir détecter ces erreurs dans du code généré automatiquement. Notre guide pour reviewer du SQL généré par IA vous donne des réflexes concrets pour auditer ces requêtes.

Questions fréquentes

Peut-on utiliser WHERE et HAVING dans la même requête ?

Oui, et c'est même recommandé. WHERE filtre les lignes avant l'agrégation, HAVING filtre les groupes après. Les combiner permet d'optimiser à la fois la performance et la précision du résultat.

Pourquoi ne peut-on pas utiliser COUNT() dans WHERE ?

Parce que WHERE est évalué avant GROUP BY. À ce stade, les agrégations n'ont pas encore été calculées. Le moteur SQL n'a donc aucune valeur de COUNT() disponible pour appliquer le filtre.

HAVING est-il plus lent que WHERE ?

Pas intrinsèquement. HAVING agit sur un ensemble déjà réduit (les groupes), ce qui peut être très rapide. Le vrai risque est d'omettre un filtre en WHERE qui aurait pu réduire le volume avant l'agrégation — là, les performances peuvent se dégrader.

Peut-on utiliser une sous-requête dans HAVING ?

Oui. Par exemple : HAVING AVG(salaire) > (SELECT AVG(salaire) FROM employes). C'est une syntaxe valide et utile pour comparer un groupe à une valeur globale.

Est-ce que HAVING fonctionne sans GROUP BY ?

Oui, techniquement. Sans GROUP BY, toute la table forme un seul groupe. Mais cette utilisation est rare et souvent source de confusion — préférez WHERE dans ce cas si aucune agrégation n'est nécessaire.

Conclusion

WHERE et HAVING ne sont pas interchangeables : chacun a son rôle précis dans la séquence d'exécution SQL. Maîtriser cette distinction vous évite des erreurs silencieuses et vous permet d'écrire des requêtes plus performantes. En entretien, c'est aussi un signal fort de rigueur technique.

La règle d'or est simple : filtrez avec WHERE tout ce qui ne dépend pas d'une agrégation, et réservez HAVING aux conditions sur les groupes calculés. Combinez les deux intelligemment pour des requêtes à la fois correctes et efficaces.

Pour mettre en pratique ces concepts avec des exercices corrigés et un environnement SQL en ligne, rendez-vous sur SQL Pratique et testez vos requêtes directement dans le navigateur.

Prêt à vous entraîner ?

50 exercices SQL interactifs avec éditeur en ligne, chronomètre et feedback IA.

Voir les exercices