Passer de la liste au chiffre
Les premières requêtes sortent des lignes. La question qui vient ensuite est presque toujours un chiffre : combien de commandes ce mois-ci, quel chiffre d'affaires par client, quel produit se vend le plus.
C'est le rôle des fonctions d'agrégation, et d'une clause de regroupement.
Les cinq fonctions utiles
SELECT
COUNT(*) AS nombre_lignes,
COUNT(email) AS nombre_emails_renseignes,
SUM(montant) AS total,
AVG(montant) AS moyenne,
MIN(date_commande) AS premiere,
MAX(date_commande) AS derniere
FROM commande;
La différence entre les deux premières est le piège classique des débutants, et elle a des conséquences réelles.
COUNT(*) compte les lignes. COUNT(colonne) compte les valeurs non nulles de cette colonne. Sur une table de mille clients dont trois cents n'ont pas d'adresse enregistrée, la première renvoie 1000 et la seconde 700.
Le même piège frappe AVG : la moyenne ignore les valeurs nulles, elle ne les compte pas comme des zéros. Une moyenne calculée sur une colonne à trous n'est pas la moyenne que vous croyez.
Regrouper
SELECT client_id, COUNT(*) AS nb_commandes, SUM(montant) AS total
FROM commande
WHERE date_commande >= '2026-01-01'
GROUP BY client_id
ORDER BY total DESC;
Règle qui évite la plupart des erreurs : tout ce qui apparaît dans le SELECT est soit dans le GROUP BY, soit dans une fonction d'agrégation. Un moteur strict refuse la requête, un moteur permissif renvoie une valeur arbitraire, ce qui est pire parce que le résultat semble juste.
WHERE ou HAVING
La confusion la plus fréquente après le regroupement, et elle se lève avec une phrase : WHERE filtre les lignes avant le regroupement, HAVING filtre les groupes après.
SELECT client_id, SUM(montant) AS total
FROM commande
WHERE statut = 'payee' -- on ne garde que les lignes payées
GROUP BY client_id
HAVING SUM(montant) > 1000; -- puis on ne garde que les gros clients
Une condition sur une colonne ordinaire va dans WHERE. Une condition sur un résultat agrégé va dans HAVING. Placer la première dans le second fonctionne parfois et coûte cher en performance, puisque les lignes inutiles ont été regroupées pour rien.
Le piège du regroupement avec jointure
Une jointure qui multiplie les lignes fausse silencieusement les sommes.
Si un client a trois adresses et que vous joignez commandes et adresses, chaque commande apparaît trois fois : SUM(montant) renvoie le triple du vrai total. Aucune erreur n'est signalée.
Le réflexe à prendre : quand une somme paraît trop grande, comptez d'abord les lignes avec COUNT(*) et comparez au nombre attendu.
À retenir
COUNT(*) compte les lignes, COUNT(colonne) les valeurs non nulles, et les moyennes ignorent les nuls. Tout ce qui n'est pas agrégé va dans le GROUP BY. WHERE avant, HAVING après. Et vérifiez le nombre de lignes quand une jointure entre en jeu.