📊sql

GROUP BY et HAVING en SQL : quand et comment

30 mars 2026 5 min de lecture

Introduction : Pourquoi regrouper des données ?

Imagine que tu as une base de données d'un magasin en ligne avec des milliers de commandes. Tu veux savoir : quel est le montant total des ventes par catégorie de produit ? Ou encore : quels clients ont passé plus de 5 commandes ? Pour répondre à ce type de questions, tu ne peux pas te contenter de simples SELECT et WHERE. Tu dois agréger et regrouper tes données. C'est exactement le rôle du duo GROUP BY et HAVING, deux clauses SQL fondamentales que tu vas rencontrer en NSI et dans tes projets.

Les fonctions d'agrégation : les outils de calcul

Avant de regrouper, il faut savoir quoi calculer sur chaque groupe. Les fonctions d'agrégation font ce travail. Les principales sont :

  • COUNT() : Compte le nombre de lignes.
  • SUM() : Fait la somme des valeurs d'une colonne numérique.
  • AVG() : Calcule la moyenne.
  • MIN() et MAX() : Trouvent la valeur minimale et maximale.

Utilisées seules, elles donnent un résultat pour toute la table. Par exemple, SELECT COUNT(*) FROM commandes; te donnera le nombre total de commandes. Mais la magie opère quand on les combine avec GROUP BY.

La clause GROUP BY : le regroupement

La clause GROUP BY permet de scinder ta table en sous-ensembles (groupes) en fonction des valeurs identiques dans une ou plusieurs colonnes. La fonction d'agrégation est ensuite appliquée sur chaque groupe indépendamment.

Syntaxe et premier exemple

La structure de base est :
SELECT colonne_a_grouper, FONCTION_AGREGAT(autre_colonne)
FROM table
GROUP BY colonne_a_grouper;

Prenons une table commandes(id, client_id, montant, date).

Question : Quel est le montant total dépensé par chaque client ?
Requête :
SELECT client_id, SUM(montant) AS total_depense
FROM commandes
GROUP BY client_id;

Le moteur SQL : 1) Regroupe toutes les lignes ayant le même client_id. 2) Pour chaque groupe (chaque client), calcule la somme des montant. 3) Renvoie une ligne par client avec son ID et son total.

Regrouper sur plusieurs colonnes

Tu peux grouper sur plusieurs critères. Par exemple, avec une table ventes(produit, ville, quantite) :
SELECT produit, ville, SUM(quantite)
FROM ventes
GROUP BY produit, ville;

Cette requête te donnera la quantité totale vendue pour chaque combinaison produit/ville.

La clause HAVING : le filtre des groupes

Maintenant, supposons que tu veuilles ne garder que les clients ayant dépensé plus de 1000€ au total. Tu pourrais être tenté d'utiliser WHERE total_depense > 1000, mais cela ne fonctionnera pas. Pourquoi ? Parce que WHERE filtre les lignes avant le regroupement et le calcul des agrégats. Ici, nous voulons filtrer après, sur le résultat de l'agrégation.

C'est le rôle de HAVING. Elle filtre les résultats après l'application de GROUP BY.

Différence cruciale : WHERE vs HAVING

  • WHERE : S'applique aux lignes individuelles de la table source. Utilise les colonnes originales. Se place avant GROUP BY.
  • HAVING : S'applique aux groupes créés. Utilise presque toujours une fonction d'agrégation ou la colonne de regroupement. Se place après GROUP BY.

Exemple complet : Clients avec plus de 5 commandes et un total > 1000€.
SELECT client_id, COUNT(*) AS nb_commandes, SUM(montant) AS total
FROM commandes
GROUP BY client_id
HAVING COUNT(*) > 5 AND SUM(montant) > 1000;

Note comment on utilise les fonctions COUNT() et SUM() directement dans la condition HAVING.

Mise en pratique avec un projet type NSI

Imaginons que tu doives analyser les données d'une bibliothèque pour ton projet NSI. Tu as une table emprunts(livre_id, usager_id, date_emprunt, duree_jours).

Objectif 1 : Trouver les 5 livres les plus empruntés.
SELECT livre_id, COUNT(*) AS fois_emprunte
FROM emprunts
GROUP BY livre_id
ORDER BY fois_emprunte DESC
LIMIT 5;

Objectif 2 : Identifier les usagers "assidus" ayant emprunté plus de 10 livres différents.
SELECT usager_id, COUNT(DISTINCT livre_id) AS livres_différents
FROM emprunts
GROUP BY usager_id
HAVING COUNT(DISTINCT livre_id) > 10;

Ici, on utilise COUNT(DISTINCT ...) pour éviter de compter deux fois le même livre emprunté par la même personne.

Objectif 3 : Calculer la durée moyenne d'emprunt par usager, mais seulement pour ceux ayant fait plus de 3 emprunts.
SELECT usager_id, AVG(duree_jours) AS duree_moyenne
FROM emprunts
GROUP BY usager_id
HAVING COUNT(*) > 3;

Pièges à éviter et bonnes pratiques

  • Colonnes dans le SELECT : Toute colonne dans le SELECT qui n'est pas dans une fonction d'agrégation doit apparaître dans le GROUP BY. Sinon, SQL ne saura pas quelle valeur afficher pour le groupe.
  • Alias dans HAVING : Certains SGBD (comme MySQL) permettent d'utiliser l'alias défini dans le SELECT (ex: HAVING total > 1000). Pour la portabilité et la clarté, privilégie l'utilisation de la fonction complète (HAVING SUM(montant) > 1000).
  • Ordre des clauses : L'ordre est logique et imposé : SELECT ... FROM ... WHERE ... GROUP BY ... HAVING ... ORDER BY ... LIMIT. Pense à "W G H O L" comme moyen mnémotechnique (Where, Group by, Having, Order by, Limit).

Le savais-tu ? En théorie des bases de données, GROUP BY correspond à l'opérateur d'algèbre relationnelle de regroupement (γ). C'est une opération fondamentale pour transformer des données brutes en informations synthétiques.

Conclusion

Maîtriser GROUP BY et HAVING, c'est passer de la simple consultation de données à leur analyse et synthèse. Tu peux désormais répondre à des questions complexes du type "combien par...", "quelle moyenne pour chaque...", "qui a dépassé tel seuil...". Ces clauses sont indispensables pour tout projet NSI impliquant une base de données, que ce soit pour un site web, une application de gestion ou une analyse de dataset. À toi de jouer : ouvre ton SGBD, crée une petite table de test et expérimente !

📚 Pour aller plus loin

Questions fréquentes

Quelle est la différence entre WHERE et HAVING ?

WHERE filtre les lignes individuelles AVANT le regroupement (GROUP BY). Il utilise les colonnes originales de la table. HAVING filtre les groupes de résultats APRÈS le regroupement. Il filtre donc sur le résultat des fonctions d'agrégation (SUM, COUNT, etc.) ou sur la colonne de regroupement. En résumé : WHERE sur les lignes, HAVING sur les groupes.

Peut-on utiliser GROUP BY sans fonction d'agrégation ?

Techniquement oui, mais cela n'aurait pas beaucoup d'intérêt. L'instruction `SELECT colonne FROM table GROUP BY colonne` est équivalente à `SELECT DISTINCT colonne FROM table`. Elle retourne les valeurs distinctes de la colonne. La puissance de GROUP BY réside justement dans sa combinaison avec les fonctions d'agrégation pour produire des calculs par catégorie.

Pourquoi mon erreur 'column must appear in the GROUP BY clause' ?

Cette erreur survient quand tu sélectionnes une colonne dans le SELECT qui n'est pas incluse dans une fonction d'agrégation (comme SUM) ET qui n'est pas listée dans la clause GROUP BY. SQL exige cela car, pour un groupe de plusieurs lignes, il ne sait pas quelle valeur unique de cette colonne afficher. Solution : soit tu ajoutes cette colonne au GROUP BY, soit tu l'enlèves du SELECT, soit tu l'englobes dans une fonction d'agrégation (comme MAX ou MIN si tu veux une valeur représentative).

Peut-on grouper par le résultat d'un calcul ou d'une fonction ?

Oui, tout à fait ! Tu peux utiliser une expression dans le GROUP BY. Par exemple, pour grouper les commandes par année : `SELECT STRFTIME('%Y', date) AS annee, SUM(montant) FROM commandes GROUP BY STRFTIME('%Y', date);`. Tu peux aussi grouper par alias défini dans le SELECT : `SELECT annee, SUM(montant) FROM (...) GROUP BY annee;`.

Bravo ! Tu as lu cet article
Inscris-toi pour sauvegarder ta progression et gagner des XP
Creer mon compte
GROUP BY SQLagregation SQL
Pixel