PostgreSQL error: 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...
^
In a grouped query, every selected column must be either part of the group key or wrapped in an aggregate — otherwise there are many candidate values per group and no rule for picking one. Databases that "helpfully" pick one anyway (as older MySQL did) return nondeterministic data; PostgreSQL refuses.
What this error means
Each result row of a GROUP BY query represents many source rows. department is fine (it defines the group), count(*) is fine (it aggregates the group) — but name? Which of the 40 employees in the department should supply it? The query is genuinely ambiguous, and the error is the SQL standard's answer.
One documented exception: group by a table's primary key, and you may select any column of that table — they are functionally dependent on the key, so there is no ambiguity. GROUP BY u.id legitimately allows SELECT u.name, u.email, ....
Common causes
- Adding a column to the SELECT of an existing grouped query without thinking about which group value it should carry.
- Porting queries from MySQL, where this historically "worked".
- Wanting something GROUP BY does not express: "the latest / top row per group" — a different query shape entirely (below).
How to diagnose it
For the flagged column, answer one question: which row's value do I actually want? "Any, they are all the same" → group by the key that makes it so (or the PK). "The max/min/sum" → aggregate. "The one from the newest row" → you want DISTINCT ON, not GROUP BY.
How to fix it
-- Il valore è determinato dal gruppo → raggruppa per la chiave:
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 è ammesso
-- Ne vuoi un aggregato:
SELECT department, count(*), max(salary) FROM employees GROUP BY department;
-- Vuoi "la riga più recente per gruppo" → DISTINCT ON:
SELECT DISTINCT ON (customer_id) *
FROM orders
ORDER BY customer_id, created_at DESC;
PostgreSQL 16 also adds any_value() for the genuine "any one will do" case.
