FondamentauxFundamentals · 29 juillet 2026 · 8 min de lecture· July 29, 2026 · 8 min read

GROUP BY, HAVING et fonctions d'agrégation : le guide complet

GROUP BY, HAVING, and Aggregate Functions: The Complete Guide

Les fonctions d'agrégation permettent de résumer plusieurs lignes en une seule valeur : total, moyenne, nombre d'éléments, etc. Combinées à GROUP BY, elles deviennent l'un des outils les plus puissants du SQL.

Aggregate functions let you summarize multiple rows into a single value: total, average, count, and so on. Combined with GROUP BY, they become one of SQL's most powerful tools.

Les fonctions d'agrégation de base

The Basic Aggregate Functions

FonctionRôle
COUNT(*)Compte le nombre de lignes
SUM(colonne)Additionne les valeurs
AVG(colonne)Calcule la moyenne
MIN(colonne) / MAX(colonne)Trouve la valeur minimale / maximale
FunctionRole
COUNT(*)Counts the number of rows
SUM(column)Adds up the values
AVG(column)Calculates the average
MIN(column) / MAX(column)Finds the minimum / maximum value
SELECT COUNT(*) AS nb_commandes, SUM(montant) AS total
FROM commandes;
SELECT COUNT(*) AS order_count, SUM(amount) AS total
FROM orders;

GROUP BY : regrouper avant d'agréger

GROUP BY: Grouping Before Aggregating

GROUP BY regroupe les lignes ayant la même valeur dans une ou plusieurs colonnes, puis applique la fonction d'agrégation à chaque groupe séparément.

GROUP BY groups rows that share the same value in one or more columns, then applies the aggregate function to each group separately.

SELECT client_id, COUNT(*) AS nb_commandes, SUM(montant) AS total
FROM commandes
GROUP BY client_id;
SELECT customer_id, COUNT(*) AS order_count, SUM(amount) AS total
FROM orders
GROUP BY customer_id;

Règle importante : toute colonne présente dans le SELECT qui n'est pas dans une fonction d'agrégation doit apparaître dans le GROUP BY.

Important rule: any column in the SELECT that isn't inside an aggregate function must appear in the GROUP BY.

HAVING : filtrer après l'agrégation

HAVING: Filtering After Aggregation

WHERE filtre les lignes avant le regroupement ; HAVING filtre les groupes après le calcul de l'agrégation. C'est la confusion la plus fréquente chez les débutants.

WHERE filters rows before grouping; HAVING filters groups after the aggregation is computed. This is the most common point of confusion for beginners.

SELECT client_id, SUM(montant) AS total
FROM commandes
WHERE montant > 0
GROUP BY client_id
HAVING SUM(montant) > 200;
SELECT customer_id, SUM(amount) AS total
FROM orders
WHERE amount > 0
GROUP BY customer_id
HAVING SUM(amount) > 200;
Astuce : vous ne pouvez pas écrire WHERE SUM(montant) > 200 — au moment où WHERE s'exécute, l'agrégation n'a pas encore eu lieu. Utilisez toujours HAVING pour filtrer sur un résultat agrégé. Tip: you can't write WHERE SUM(amount) > 200 — at the point WHERE runs, aggregation hasn't happened yet. Always use HAVING to filter on an aggregated result.

L'ordre réel d'exécution d'une requête SQL

The Actual Execution Order of a SQL Query

Contrairement à l'ordre dans lequel on écrit une requête, le moteur SQL l'exécute dans cet ordre logique :

Unlike the order in which you write a query, the SQL engine executes it in this logical order:

  1. FROM — identifier les tables
  2. WHERE — filtrer les lignes individuelles
  3. GROUP BY — regrouper les lignes restantes
  4. HAVING — filtrer les groupes
  5. SELECT — choisir les colonnes et calculer les agrégations
  6. ORDER BY — trier le résultat final
  7. LIMIT — limiter le nombre de lignes renvoyées
  1. FROM — identify the tables
  2. WHERE — filter individual rows
  3. GROUP BY — group the remaining rows
  4. HAVING — filter the groups
  5. SELECT — choose columns and compute aggregations
  6. ORDER BY — sort the final result
  7. LIMIT — limit the number of rows returned

Comprendre cet ordre explique pourquoi on ne peut pas utiliser un alias du SELECT dans le WHERE, mais qu'on peut souvent l'utiliser dans ORDER BY.

Understanding this order explains why you can't use a SELECT alias in WHERE, but can often use it in ORDER BY.

Exemple complet

Full Example

SELECT
  c.nom,
  COUNT(co.id) AS nb_commandes,
  SUM(co.montant) AS total_depense
FROM clients c
LEFT JOIN commandes co ON co.client_id = c.id
GROUP BY c.nom
HAVING COUNT(co.id) >= 1
ORDER BY total_depense DESC
LIMIT 10;
SELECT
  c.name,
  COUNT(o.id) AS order_count,
  SUM(o.amount) AS total_spent
FROM customers c
LEFT JOIN orders o ON o.customer_id = c.id
GROUP BY c.name
HAVING COUNT(o.id) >= 1
ORDER BY total_spent DESC
LIMIT 10;

Cette requête retourne les 10 clients ayant dépensé le plus, classés par montant décroissant, en excluant ceux sans aucune commande.

This query returns the top 10 highest-spending customers, ranked in descending order, excluding those with no orders at all.

← Article précédent : Les sous-requêtes ← Previous article: Subqueries Article suivant : Transactions et ACID → Next article: Transactions and ACID →
Publicité Advertisement