← Tous les articles
Base de données

GROUP BY et fonctions d’agrégation SQL : COUNT, SUM, AVG, MIN, MAX

23 juillet 2026 · par Romain RICHER

Compter le nombre de commandes par client, calculer le chiffre d’affaires par région, trouver le salaire moyen par service… Dès qu’il s’agit de résumer des données plutôt que de les lister ligne par ligne, deux outils SQL entrent en jeu : les fonctions d’agrégation (COUNT, SUM, AVG, MIN, MAX) et la clause GROUP BY. Ensemble, ils transforment des milliers de lignes en une synthèse lisible.

Cet article explique comment les utiliser, seuls puis combinés, avec des exemples concrets et leur résultat. Il fait suite à notre présentation des requêtes SQL essentielles.

Le jeu de données d’exemple

Les exemples s’appuient sur une table employes :

nom service salaire
Martin Informatique 3200
Durand Comptabilité 2800
Petit Informatique 3600
Moreau Comptabilité 2900
Leroy Informatique 4100

Les fonctions d’agrégation seules

Une fonction d’agrégation prend une colonne entière et en renvoie une seule valeur. Sans GROUP BY, elle s’applique à toute la table :

SELECT COUNT(*) AS nb_employes,
       SUM(salaire) AS masse_salariale,
       AVG(salaire) AS salaire_moyen,
       MIN(salaire) AS salaire_min,
       MAX(salaire) AS salaire_max
FROM employes;

Résultat :

nb_employes masse_salariale salaire_moyen salaire_min salaire_max
5 16600 3320 2800 4100

Chaque fonction a son rôle :

  • COUNT(*) compte les lignes. COUNT(colonne) compte les valeurs non NULL de cette colonne — une nuance importante.
  • SUM additionne, AVG fait la moyenne (sur les valeurs non NULL uniquement).
  • MIN et MAX renvoient les valeurs extrêmes, y compris sur du texte ou des dates (ordre alphabétique, chronologique).

GROUP BY : agréger par groupe

C’est là que tout devient puissant. GROUP BY découpe les lignes en groupes partageant une même valeur, puis applique la fonction d’agrégation à chaque groupe séparément. Pour obtenir le salaire moyen par service :

SELECT service,
       COUNT(*) AS effectif,
       AVG(salaire) AS salaire_moyen
FROM employes
GROUP BY service;

Résultat :

service effectif salaire_moyen
Informatique 3 3633,33
Comptabilité 2 2850

La base a regroupé les 5 lignes en 2 groupes (un par service) et calculé l’effectif et la moyenne de chacun. La règle d’or à retenir : toute colonne du SELECT qui n’est pas dans une fonction d’agrégation doit figurer dans le GROUP BY. Sinon, la base renvoie une erreur (ou, pire, un résultat imprévisible sur certains moteurs permissifs).

HAVING : filtrer les groupes

Comment ne garder que les services dont le salaire moyen dépasse 3000 ? On pourrait penser à WHERE, mais il ne fonctionne pas ici : WHERE filtre les lignes avant le regroupement, alors qu’on veut filtrer après, sur le résultat de l’agrégation. C’est le rôle de HAVING :

SELECT service,
       AVG(salaire) AS salaire_moyen
FROM employes
GROUP BY service
HAVING AVG(salaire) > 3000;

Résultat :

service salaire_moyen
Informatique 3633,33

La Comptabilité (moyenne 2850) est écartée. Retenez la distinction, c’est la question d’entretien classique :

  • WHERE filtre les lignes, avant le GROUP BY.
  • HAVING filtre les groupes, après le GROUP BY, et peut porter sur une fonction d’agrégation.

L’ordre des clauses

Une requête complète respecte toujours cet ordre d’écriture — l’inverser provoque une erreur de syntaxe :

SELECT   colonnes, agrégations
FROM     table
WHERE    condition sur les lignes
GROUP BY colonnes de regroupement
HAVING   condition sur les groupes
ORDER BY tri du résultat;

Un exemple qui combine tout — l’effectif par service, en ne comptant que les salaires supérieurs à 2500, pour les services d’au moins 2 personnes, triés par effectif décroissant :

SELECT service, COUNT(*) AS effectif
FROM employes
WHERE salaire > 2500
GROUP BY service
HAVING COUNT(*) >= 2
ORDER BY effectif DESC;

GROUP BY et jointures : le duo gagnant

En pratique, on agrège très souvent le résultat d’une jointure. Par exemple, pour compter le nombre d’employés par libellé de service (quand le libellé est dans une autre table), on combine une jointure SQL et un GROUP BY :

SELECT s.libelle, COUNT(e.id_employe) AS effectif
FROM services s
LEFT JOIN employes e ON e.id_service = s.id_service
GROUP BY s.libelle;

Le LEFT JOIN garde tous les services (même vides), et COUNT(e.id_employe) renvoie 0 pour ceux sans employé — puisque COUNT d’une colonne ignore les NULL. C’est un motif extrêmement courant.

Points d’attention

  • COUNT(*) vs COUNT(colonne) : le premier compte toutes les lignes, le second ignore les NULL de la colonne. Choisissez en connaissance de cause.
  • AVG ignore les NULL : la moyenne se calcule sur les valeurs présentes, pas sur le nombre total de lignes. Si vous voulez traiter les NULL comme des zéros, utilisez AVG(COALESCE(colonne, 0)).
  • Alias non utilisables dans HAVING/WHERE : sur la plupart des moteurs, vous ne pouvez pas réutiliser un alias du SELECT dans le HAVING ; répétez la fonction d’agrégation.
  • Message d’erreur ? Un oubli de colonne dans le GROUP BY est une cause classique d’erreur ; voyez notre guide des erreurs Oracle courantes si vous êtes sur Oracle.

En résumé

Les fonctions d’agrégation résument une colonne en une valeur ; GROUP BY applique ce résumé groupe par groupe ; HAVING filtre ensuite les groupes obtenus. Gardez en tête la règle d’or (toute colonne non agrégée du SELECT va dans le GROUP BY) et la distinction WHERE / HAVING (avant / après regroupement). Avec ces principes, vous passez de longues listes de données à des synthèses claires — le cœur de l’analyse en SQL.

Laisser un commentaire

Votre adresse e-mail ne sera pas publiée. Les commentaires sont modérés avant publication.