SQL GROUP BY : calculer par groupe
Les fonctions d'agrégation résument toute une table en une seule valeur. Mais on veut souvent un résultat par catégorie : le nombre de clients par ville, le chiffre d'affaires par mois, le salaire moyen par département. C'est le rôle de GROUP BY.
Syntaxe
SELECT colonne_de_groupe, FONCTION(colonne)
FROM table
GROUP BY colonne_de_groupe;Comment ça marche
GROUP BY rassemble les lignes qui ont la même valeur dans la colonne indiquée, puis applique la fonction d'agrégation à chaque groupe. Le résultat contient une ligne par groupe.
La règle d'or
Chaque colonne du SELECT doit soit figurer dans le GROUP BY, soit être à l'intérieur d'une fonction d'agrégation. Sinon, SQL ne saurait pas quelle valeur afficher pour un groupe qui contient plusieurs lignes différentes.
L'ordre d'exécution d'une requête
SQL n'exécute pas les clauses dans l'ordre où on les écrit :
FROM(et lesJOIN) : on part des tables ;WHERE: on filtre les lignes ;GROUP BY: on forme les groupes ;HAVING: on filtre les groupes ;SELECT: on calcule les colonnes ;ORDER BYpuisLIMIT.
Comprendre cet ordre explique la plupart des erreurs : par exemple, on ne peut pas utiliser un COUNT dans le WHERE, car les groupes n'existent pas encore à ce moment-là.
Schéma
| prenom | ville |
|---|---|
| Léa | Lyon |
| Inès | Lyon |
| Hugo | Paris |
| Adam | Lyon |
| Zoé | Paris |
| ville | COUNT(*) |
|---|---|
| Lyon | 3 |
| Paris | 2 |
Schéma simplifié pour illustrer le principe. Les exemples ci-dessous utilisent la vraie base d'exercices de SQL Quest (une boutique en ligne fictive : voir le schéma complet).
Exemples avec leurs résultats
1. Compter par groupe
Le nombre de clients par ville, de la plus peuplée à la moins peuplée.
SELECT ville, COUNT(*) AS nb_clients
FROM clients
GROUP BY ville
ORDER BY nb_clients DESC; Essayer dans le bac à sable| ville | nb_clients |
|---|---|
| Bordeaux | 14 |
| Paris | 13 |
| Lyon | 12 |
| Strasbourg | 11 |
| Nantes | 10 |
| Montréal | 10 |
| Marseille | 10 |
| Lille | 10 |
| Casablanca | 10 |
| Bruxelles | 9 |
12 lignes au total · 10 affichées
2. Plusieurs agrégations par groupe
Pour chaque catégorie : le nombre de produits et le prix moyen.
SELECT categorie, COUNT(*) AS nb_produits, ROUND(AVG(prix), 2) AS prix_moyen
FROM produits
GROUP BY categorie; Essayer dans le bac à sable| categorie | nb_produits | prix_moyen |
|---|---|---|
| Alimentation | 5 | 24,74 |
| Informatique | 7 | 146,43 |
| Livres | 5 | 18,17 |
| Maison | 6 | 36,45 |
| Sport | 6 | 27,81 |
5 lignes au total
3. Grouper sur une expression
Le nombre de commandes par année, grâce à strftime qui extrait l'année d'une date.
SELECT strftime('%Y', date_commande) AS annee, COUNT(*) AS nb_commandes
FROM commandes
GROUP BY annee; Essayer dans le bac à sable| annee | nb_commandes |
|---|---|
| 2023 | 190 |
| 2024 | 214 |
| 2025 | 196 |
3 lignes au total
4. Grouper sur deux colonnes
Le nombre de commandes par année et par statut.
SELECT strftime('%Y', date_commande) AS annee, statut, COUNT(*) AS nb
FROM commandes
GROUP BY annee, statut
ORDER BY annee, nb DESC
LIMIT 8; Essayer dans le bac à sable| annee | statut | nb |
|---|---|---|
| 2023 | livrée | 85 |
| 2023 | annulée | 39 |
| 2023 | en cours | 34 |
| 2023 | expédiée | 32 |
| 2024 | livrée | 117 |
| 2024 | expédiée | 35 |
| 2024 | en cours | 34 |
| 2024 | annulée | 28 |
8 lignes au total
Les erreurs fréquentes
Afficher une colonne qui n'est pas groupée
nom n'est ni dans le GROUP BY ni dans une agrégation : SQLite affiche un nom au hasard du groupe, les autres bases renvoient une erreur.
SELECT ville, nom, COUNT(*) FROM clients GROUP BY ville;SELECT ville, COUNT(*) FROM clients GROUP BY ville;Oublier le GROUP BY
Sans GROUP BY, la requête renvoie une seule ligne pour toute la table au lieu d'une ligne par ville.
SELECT ville, COUNT(*) FROM clients;SELECT ville, COUNT(*) FROM clients GROUP BY ville;Grouper sur une colonne trop précise
Grouper par id crée un groupe par ligne : le regroupement ne sert à rien.
SELECT id, ville, COUNT(*) FROM clients GROUP BY id;SELECT ville, COUNT(*) FROM clients GROUP BY ville;Exercices
Essayez d'écrire la requête vous-même avant d'ouvrir la solution.
Défi 1. Affichez le salaire moyen par département, arrondi à l'euro.
Voir une solution
SELECT departement, ROUND(AVG(salaire)) AS salaire_moyen FROM employes GROUP BY departement;| departement | salaire_moyen |
|---|---|
| Direction | 9 500 |
| IT | 4 760 |
| RH | 4 233 |
| Ventes | 4 554 |
4 lignes au total
Essayer dans le bac à sableDéfi 2. Affichez le nombre de produits par fournisseur (fournisseur_id, nombre).
Voir une solution
SELECT fournisseur_id, COUNT(*) AS nb FROM produits GROUP BY fournisseur_id;| fournisseur_id | nb |
|---|---|
| 1 | 1 |
| 2 | 2 |
| 3 | 4 |
| 4 | 13 |
| 5 | 1 |
| 6 | 5 |
| 7 | 3 |
7 lignes au total
Essayer dans le bac à sableLes exercices interactifs sont corrigés automatiquement, avec un prof qui explique vos erreurs. Une leçon résumée reste affichée à côté de l'éditeur.
Questions fréquentes
Quelle différence entre GROUP BY et ORDER BY ?
GROUP BY rassemble les lignes pour calculer une valeur par groupe (le nombre de lignes diminue). ORDER BY ne fait que trier les lignes, sans en changer le nombre.
Peut-on utiliser un alias dans GROUP BY ?
SQLite, MySQL et PostgreSQL l'acceptent (GROUP BY annee). Le SQL standard et SQL Server demandent de répéter l'expression.
Comment filtrer les groupes ?
Avec HAVING, placé après GROUP BY : HAVING COUNT(*) > 10 ne garde que les groupes de plus de 10 lignes.