Erreur PostgreSQL : column must appear in the GROUP BY clause
ERROR: column "employees.name" must appear in the GROUP BY clause or be used in an aggregate function
LINE 1: SELECT department, name, count(*) FROM employees GROUP BY d...
^
Dans une requête groupée, chaque colonne sélectionnée doit soit faire partie de la clé de regroupement, soit être enveloppée dans un agrégat — sinon il y a de nombreuses valeurs candidates par groupe et aucune règle pour en choisir une. Les bases qui en choisissent une « obligeamment » quand même (comme le faisait l'ancien MySQL) renvoient des données non déterministes ; PostgreSQL refuse.
Ce que signifie cette erreur
Chaque ligne de résultat d'une requête GROUP BY représente de nombreuses lignes sources. department convient (il définit le groupe), count(*) convient (il agrège le groupe) — mais name ? Lequel des 40 employés du service devrait le fournir ? La requête est réellement ambiguë, et l'erreur est la réponse du standard SQL.
Une exception documentée : groupez par la clé primaire d'une table, et vous pouvez sélectionner n'importe quelle colonne de cette table — elles dépendent fonctionnellement de la clé, il n'y a donc pas d'ambiguïté. GROUP BY u.id autorise légitimement SELECT u.name, u.email, ....
Causes fréquentes
- Ajouter une colonne au SELECT d'une requête groupée existante sans réfléchir à quelle valeur de groupe elle devrait porter.
- Porter des requêtes depuis MySQL, où cela « fonctionnait » historiquement.
- Vouloir quelque chose que GROUP BY n'exprime pas : « la dernière / meilleure ligne par groupe » — une forme de requête entièrement différente (ci-dessous).
Comment la diagnostiquer
Pour la colonne signalée, répondez à une question : la valeur de quelle ligne veux-je réellement ? « N'importe laquelle, elles sont toutes identiques » → groupez par la clé qui rend cela vrai (ou la PK). « Le max/min/somme » → agrégez. « Celle de la ligne la plus récente » → vous voulez DISTINCT ON, pas GROUP BY.
Comment la corriger
-- La valeur est déterminée par le groupe → groupez par la clé :
SELECT u.id, u.name, count(o.id)
FROM users u JOIN orders o ON o.user_id = u.id
GROUP BY u.id; -- PK : u.name est admis
-- Vous en voulez un agrégat :
SELECT department, count(*), max(salary) FROM employees GROUP BY department;
-- Vous voulez « la ligne la plus récente par groupe » → DISTINCT ON :
SELECT DISTINCT ON (customer_id) *
FROM orders
ORDER BY customer_id, created_at DESC;
PostgreSQL 16 ajoute aussi any_value() pour le vrai cas « n'importe laquelle fera l'affaire ».
