SQL GROUP BY et fonctions d'agrégation : résumez vos données
Published: 2026-04-08
GROUP BY regroupe plusieurs lignes qui partagent la même valeur dans une ou plusieurs colonnes en une seule ligne de synthèse. Combiné avec des fonctions d’agrégation comme COUNT, SUM, AVG, MIN et MAX, c’est la base de presque toutes les requêtes de reporting et d’analytique. GROUP BY est pris en charge dans toutes les bases SQL, y compris SQLite, PostgreSQL, MySQL, SQL Server et Oracle.
Données d’exemple
Nous utilisons deux tables dans tous les exemples :
Table employees :
| id | name | department | hire_date | salary |
|---|---|---|---|---|
| 1 | Alice | Engineering | 2023-01-15 | 95000 |
| 2 | Bob | Engineering | 2023-06-01 | 85000 |
| 3 | Carol | Engineering | 2024-03-10 | 85000 |
| 4 | Dave | Sales | 2023-02-20 | 72000 |
| 5 | Eve | Sales | 2023-09-05 | 68000 |
| 6 | Frank | Sales | 2024-01-15 | 65000 |
| 7 | Grace | Marketing | 2023-04-01 | 82000 |
| 8 | Henry | Marketing | 2024-06-01 | 70000 |
Table orders :
| id | customer | product | category | quantity | unit_price | order_date | status |
|---|---|---|---|---|---|---|---|
| 1 | Acme Corp | Laptop Pro | Electronics | 3 | 1299.99 | 2026-01-05 | delivered |
| 2 | Acme Corp | Wireless Mouse | Electronics | 10 | 29.99 | 2026-01-12 | delivered |
| 3 | Globex | Office Chair | Furniture | 5 | 249.99 | 2026-01-18 | delivered |
| 4 | Globex | Standing Desk | Furniture | 2 | 599.99 | 2026-01-20 | shipped |
| 5 | Initech | Notebook Pack | Stationery | 20 | 12.99 | 2026-02-03 | delivered |
| 6 | Initech | Pen Set | Stationery | 15 | 8.99 | 2026-02-07 | delivered |
| 7 | Acme Corp | Monitor 27" | Electronics | 4 | 399.99 | 2026-02-14 | delivered |
| 8 | Umbrella Ltd | Laptop Pro | Electronics | 2 | 1299.99 | 2026-02-20 | cancelled |
| 9 | Umbrella Ltd | Desk Lamp | Furniture | 8 | 39.99 | 2026-03-01 | delivered |
| 10 | Globex | Wireless Mouse | Electronics | 12 | 29.99 | 2026-03-05 | shipped |
| 11 | Initech | Monitor 27" | Electronics | 1 | 399.99 | 2026-03-10 | delivered |
| 12 | Acme Corp | Standing Desk | Furniture | 1 | 599.99 | 2026-03-15 | processing |
Syntaxe de GROUP BY
SELECT column1, aggregate_function(column2)
FROM table_name
WHERE condition
GROUP BY column1
HAVING aggregate_condition
ORDER BY column1;
- GROUP BY — une ou plusieurs colonnes dont les combinaisons de valeurs distinctes définissent chaque groupe
- Fonctions d’agrégation — calculent une seule valeur à partir de toutes les lignes du groupe
- HAVING — filtre les groupes (comme WHERE, mais pour les résultats groupés)
- Chaque colonne dans SELECT qui n’est pas à l’intérieur d’une agrégation doit apparaître dans GROUP BY
Ordre d’exécution SQL
Les clauses SQL sont écrites dans un certain ordre mais exécutées dans un ordre différent. Comprendre cela aide à expliquer pourquoi HAVING peut référencer des fonctions d’agrégation mais pas WHERE, et pourquoi vous ne pouvez pas utiliser un alias de SELECT dans une clause HAVING.
FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY
| Étape | Clause | Ce qui se passe |
|---|---|---|
| 1 | FROM | Charge la ou les tables et évalue les JOIN |
| 2 | WHERE | Filtre les lignes individuelles — les fonctions d’agrégation ne sont pas autorisées ici |
| 3 | GROUP BY | Regroupe les lignes restantes en groupes |
| 4 | HAVING | Filtre les groupes — les fonctions d’agrégation sont autorisées ici |
| 5 | SELECT | Calcule les colonnes de sortie et les alias |
| 6 | ORDER BY | Trie le jeu de résultats final |
C’est pourquoi WHERE status = 'delivered' s’exécute avant le regroupement (filtre rapide au niveau des lignes), tandis que HAVING COUNT(*) > 2 s’exécute après le regroupement (filtre des groupes entiers).
COUNT()
COUNT(*) compte toutes les lignes d’un groupe. COUNT(column) compte les valeurs non NULL dans cette colonne.
Exemple : nombre d’employés par département
Exemple : nombre de commandes par client
Exemple : compter les commandes livrées vs autres statuts
Comptez uniquement les commandes correspondant à une condition en utilisant COUNT avec une expression CASE :
SUM()
SUM(column) additionne toutes les valeurs du groupe pour une colonne numérique.
Exemple : masse salariale totale par département
Exemple : chiffre d’affaires total par catégorie
Calculez le chiffre d’affaires comme quantity * unit_price :
Exemple : chiffre d’affaires par client et par catégorie
Regroupez par plusieurs colonnes pour détailler davantage le chiffre d’affaires :
AVG()
AVG(column) renvoie la moyenne arithmétique de toutes les valeurs non NULL du groupe.
Exemple : salaire moyen par département
Exemple : valeur moyenne de commande par client
MIN() et MAX()
MIN(column) et MAX(column) renvoient respectivement les plus petites et plus grandes valeurs du groupe.
Exemple : fourchette de salaires par département
Exemple : première et dernière date de commande par client
Combiner plusieurs agrégations
Vous pouvez combiner n’importe quel nombre de fonctions d’agrégation dans une seule requête.
Exemple : synthèse complète par département
Exemple : synthèse des commandes par client
HAVING
HAVING filtre les groupes après agrégation — c’est l’équivalent de WHERE pour les résultats groupés.
Exemple : départements avec plus de deux employés
Exemple : clients avec un chiffre d’affaires total supérieur à 2000
Exemple : catégories avec une valeur moyenne de commande inférieure à 500
WHERE vs. HAVING
WHERE filtre les lignes individuelles avant le regroupement. HAVING filtre les groupes après l’agrégation.
Exemple : chiffre d’affaires des seules commandes livrées par client
Utilisez WHERE pour exclure des lignes avant le regroupement, puis HAVING pour filtrer les résultats :
GROUP BY avec des JOIN
Vous pouvez regrouper des données couvrant plusieurs tables en les joignant d’abord.
Exemple : chiffre d’affaires par département via une jointure sur employees
Exemple : nombre de commandes et chiffre d’affaires par catégorie et par mois
GROUP BY avec des expressions
Vous pouvez regrouper par des expressions calculées, pas seulement par des colonnes simples.
Exemple : employés embauchés par année
Exemple : commandes par mois
COUNT(DISTINCT)
COUNT(DISTINCT column) compte le nombre de valeurs uniques dans le groupe.
Exemple : nombre de produits uniques commandés par client
Filtrer les groupes avec plusieurs conditions
HAVING prend en charge toute expression booléenne, y compris les combinaisons AND/OR.
Exemple : clients actifs à forte valeur
Trouvez les clients avec plus d’une commande et un chiffre d’affaires total supérieur à 1000 :
Exemple pratique : rapport de ventes
Combinez tout pour obtenir un rapport de ventes complet.
Exemple : rapport de performance par catégorie
Exemple : produit le plus rentable
GROUP BY vs. fonctions de fenêtre
GROUP BY regroupe les lignes en une ligne par groupe. Les fonctions de fenêtre conservent toutes les lignes et ajoutent une colonne calculée — voir le tutoriel sur les fonctions de fenêtre SQL pour plus de détails.
Exemple : GROUP BY renvoie une ligne par département
Exemple : une fonction de fenêtre conserve toutes les lignes
Cas d’usage courants de GROUP BY
- Tableaux de bord de reporting — Résumer totaux, moyennes et comptes par catégorie ou période
- Analyse des effectifs — Compter les employés, utilisateurs ou enregistrements par groupe
- Répartition du chiffre d’affaires — Total et moyenne par produit, région ou client
- Analyse de tendances — Regrouper par mois ou année pour repérer les évolutions dans le temps
- Top-N par groupe — Combiner avec des sous-requêtes ou des CTE pour trouver le meilleur élément dans chaque groupe
- Validation des données — Compter les doublons ou les valeurs NULL par groupe
- Analyse de cohortes — Regrouper les utilisateurs par date d’inscription ou segment de comportement
Conseils de performance
- Indexer les colonnes de GROUP BY — Les index sur les colonnes de regroupement accélèrent l’étape de tri et de regroupement
- Filtrer tôt avec WHERE — Réduire les lignes avant le regroupement avec WHERE est plus rapide que filtrer après avec HAVING
- Éviter SELECT * — Ne sélectionnez que les colonnes dont vous avez réellement besoin ; les agrégations profitent de données plus étroites
- Utiliser des index couvrants — Un index qui inclut à la fois la colonne de GROUP BY et la colonne agrégée peut éviter un scan complet de la table
- Envisager des vues matérialisées — Pour des agrégations fréquentes sur de grandes tables, certaines bases permettent des synthèses pré-calculées
Récapitulatif
- GROUP BY regroupe les lignes qui partagent les mêmes valeurs de colonnes en une ligne de synthèse par combinaison unique
- COUNT(*) compte toutes les lignes ; COUNT(column) compte les valeurs non NULL ; COUNT(DISTINCT column) compte les valeurs uniques
- SUM totalise les valeurs numériques ; AVG calcule la moyenne ; MIN / MAX trouvent les bornes
- Chaque colonne de SELECT doit soit apparaître dans GROUP BY, soit être enveloppée dans une fonction d’agrégation
- WHERE filtre les lignes avant le regroupement ; HAVING filtre les groupes après agrégation
- Vous pouvez faire un GROUP BY sur des expressions (par exemple
SUBSTR(date, 1, 7)pour un regroupement au niveau du mois) - Joindre des tables avant le regroupement vous permet de combiner des données de plusieurs sources dans un seul rapport
- Utilisez des fonctions de fenêtre plutôt que GROUP BY lorsque vous avez besoin de métriques au niveau du groupe sans perdre les lignes individuelles
Essayez de combiner GROUP BY avec des JOIN, des expressions CASE et des clauses HAVING pour construire les rapports dont votre analyse de données a besoin !