La clause SQL GROUP BY regroupe les lignes en fonction d’un ou plusieurs champs afin de créer des synthèses utiles. Elle s’utilise toujours avec des fonctions de comptage comme COUNT ou SUM et répond aux besoins d’analyse et de reporting.
Table des matières
Qu’est-ce que la clause SQL GROUP BY ?
La clause GROUP BY organise les enregistrements de la table par valeurs identiques dans une ou plusieurs colonnes. Chaque groupe reçoit ensuite une fonction d’agrégation qui calcule un résultat synthétique. Cette approche synthétise des volumes importants de données en quelques lignes représentatives. La requête de sélection suivante classe les clients par ville et compte le nombre dans chaque groupe. La fonction COUNT(*) examine toutes les lignes de chaque ville. Le résultat affiche une ligne par ville avec son nombre total de clients.
SELECT ville, COUNT(*) AS nb_clients
FROM clients
GROUP BY ville;
Les fonctions d’agrégation avec GROUP BY
Les fonctions d’agrégation calculent un résultat unique pour chaque groupe créé par GROUP BY.
Effectuer des requêtes avec COUNT et un Alias pour les effectifs
La fonction COUNT détermine le nombre de lignes dans chaque groupe. Cette fonction compte toutes les lignes y compris celles avec des valeurs NULL. COUNT(colonne) ignore les lignes où cette colonne vaut NULL. La requête ci-dessous affiche le nombre de commandes par statut en constituant un groupe distinct. Le résultat synthétise l’activité globale par étape du processus.
SELECT statut, COUNT(*) AS total_commandes
FROM commandes
GROUP BY statut;
Effectuer une requête avec SUM pour les totaux
SUM additionne les valeurs numériques de chaque groupe. La requête suivante calcule le chiffre d’affaires par catégorie de produits. L’expression prix multiplié par quantité crée le montant total par ligne et SUM additionne tous ces montants au sein de chaque groupe de catégorie.
SELECT categorie, SUM(prix * quantite) AS chiffre_affaires
FROM ventes
GROUP BY categorie;
Réaliser des requêtes avec AVG pour les moyennes
AVG calcule la moyenne arithmétique des valeurs numériques d’un groupe. Cette fonction divise la somme par le nombre de valeurs non-NULL. La requête ci-dessous détermine l’âge moyen des clients par ville en ignorant les âges NULL dans le calcul. Le résultat aide à comprendre le profil démographique de chaque zone géographique.
SELECT ville, AVG(age) AS age_moyen
FROM clients
GROUP BY ville;
Requêtes plus complexes avec MIN et MAX pour les extrêmes
MIN sélectionne la valeur minimale d’un groupe alors que MAX sélectionne la valeur maximale du même groupe. MIN et MAX fonctionnent avec les nombres, les dates et les chaînes de caractères. La prochaine requête identifie les prix extrêmes pratiqués par chaque fournisseur.
SELECT fournisseur, MIN(prix) AS prix_min, MAX(prix) AS prix_max
FROM produits
GROUP BY fournisseur;
Exemples de requêtes complexes avec GROUP BY
Cette requête analyse les commandes du début 2026 par statut. WHERE limite d’abord à l’année en cours puis GROUP BY et SUM calculent les totaux par statut avec tri final.
SELECT statut_commande, SUM(montant) AS total
FROM commandes
WHERE date_commande >= '2026-01-01'
GROUP BY statut_commande
HAVING SUM(montant) > 5000
ORDER BY total DESC;
La requête suivante montre une jointure entre plusieurs tables grâce à la clé primaire et la clé étrangère. Le résultat de la requête suivante détermine le panier moyen par ville. Les jointures assemblent clients, commandes et produits puis GROUP BY synthétise les prix moyens par zone géographique.
SELECT c.ville, AVG(p.prix) AS prix_moyen
FROM clients c
JOIN commandes com ON c.id = com.client_id
JOIN produits p ON com.produit_id = p.id
GROUP BY c.ville;
Voici une requête utilisant GROUP BY avec des dates, ce qui constitue un cas fréquent en reporting. La prochaine requête permet de filtrer les commandes par mois et année. Les fonctions YEAR et MONTH extraient les composants de date et GROUP BY regroupe par combinaison mois/année avec tri chronologique inversé.
SELECT YEAR(date_commande) AS annee,
MONTH(date_commande) AS mois,
COUNT(*) AS nb_commandes
FROM commandes
GROUP BY YEAR(date_commande), MONTH(date_commande)
ORDER BY annee DESC, mois DESC;
La règle des colonnes orphelines et syntaxe SQL
Une règle fondamentale régit la clause GROUP BY : toutes les colonnes non-agrégées du SELECT doivent apparaître dans GROUP BY. Cette contrainte garantit la cohérence logique des résultats et la violation de cette contrainte provoque une erreur de syntaxe.
-- ❌ ERREUR : nom "orphelin"
SELECT ville, nom, COUNT(*)
FROM clients
GROUP BY ville;
-- ✅ CORRECT
SELECT ville, COUNT(*)
FROM clients
GROUP BY ville;
La colonne nom disparaît car elle varie à l’intérieur du groupe ville. Le mot-clé GROUP BY produit une ligne unique par valeur de ville. Une colonne variable comme nom rend le résultat ambigu. Cette règle surprend souvent ceux qui débutent avec le langage SQL. Les SGBD stricts (PostgreSQL) rejettent immédiatement la requête erronée, tandis que MySQL offre parfois une tolérance configurable qui masque le problème.
Erreurs avec GROUP BY à éviter lors de la création d’une requête
Les débutants commettent fréquemment les mêmes erreurs avec GROUP BY. Oublier une fonction d’agrégation constitue l’erreur la plus commune car la base de données exige toujours une synthèse par groupe.
-- ❌ SANS FONCTION
SELECT ville
FROM clients
GROUP BY ville; -- ERREUR !
-- ✅ AVEC FONCTION
SELECT ville, COUNT(*)
FROM clients
GROUP BY ville;
Une autre erreur est de placer HAVING avant GROUP BY. L’ordre logique impose GROUP BY avant HAVING. Cette inversion provoque une erreur fatale de syntaxe. Utiliser une requête simple SELECT * avec GROUP BY provoque aussi une erreur systématique. L’astérisque (*) sélectionne toutes les colonnes sans distinction mais GROUP BY ne peut pas gérer cette ambiguïté massive.
-- ❌ ORDRE FAUX
SELECT ville, COUNT(*)
FROM clients
HAVING COUNT(*) > 10 -- ERREUR !
GROUP BY ville;
-- ✅ ORDRE CORRECT
SELECT ville, COUNT(*)
FROM clients
GROUP BY ville
HAVING COUNT(*) > 10;
Bonnes pratiques lors de l’utilisation de GROUP BY
Créez des index sur les colonnes utilisées dans le GROUP BY car un index accélère le regroupement sur les grandes tables. La base de données trie automatiquement les valeurs indexées lors du GROUP BY.
Ajoutez toujours ORDER BY après GROUP BY pour un affichage logique. Les résultats des regroupements arrivent souvent dans l’ordre arbitraire du stockage physique. ORDER BY DESC sur les totaux classe les groupes par importance décroissante.
Utilisez LIMIT après GROUP BY pour paginer les résultats synthétiques ce qui évite de charger des milliers de groupes inutiles. Cette technique optimise particulièrement les rapports volumineux.
Vérifiez la logique de vos regroupements sur un échantillon réduit en ajoutant LIMIT 10 avant d’exécuter la requête en production. Cette approche vérifie la logique avant exécution de la requête en production. Les erreurs de regroupement se détectent rapidement sur de petits volumes.
Documentez toujours les requêtes complexes avec des commentaires. Expliquez le rôle de chaque colonne dans GROUP BY et HAVING. ce qui facilite la maintenance par d’autres développeurs.
Vérification des connaissances
Appliquez maintenant les concepts appris avec ces exercices pratiques.
Exercice 1 : Calculez le nombre de commandes par mois pour 2026 :
SELECT _________, COUNT(*)
FROM commandes
WHERE _________
GROUP BY _________;
-- ✅ SELECT MONTH(date_commande), COUNT(*)
FROM commandes
WHERE date_commande >= '2026-01-01' GROUP BY MONTH(date_commande);
Exercice 2 : Corrigez cette erreur :
SELECT ville, nom, AVG(age)
FROM clients
GROUP BY ville;
-- ✅ SELECT ville, AVG(age)
FROM clients
GROUP BY ville;
Sources: MySql, Postgresql, SQL Server