Errore 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...
^
In una query raggruppata, ogni colonna selezionata deve essere o parte della chiave di raggruppamento o avvolta in un aggregato — altrimenti ci sono molti valori candidati per gruppo e nessuna regola per sceglierne uno. I database che "premurosamente" ne scelgono uno comunque (come faceva MySQL più vecchio) restituiscono dati non deterministici; PostgreSQL rifiuta.
Cosa significa questo errore
Ogni riga di risultato di una query GROUP BY rappresenta molte righe sorgente. department va bene (definisce il gruppo), count(*) va bene (aggrega il gruppo) — ma name? Quale dei 40 dipendenti del reparto dovrebbe fornirlo? La query è genuinamente ambigua, e l'errore è la risposta dello standard SQL.
Un'eccezione documentata: raggruppa per la primary key di una tabella, e puoi selezionare qualsiasi colonna di quella tabella — sono funzionalmente dipendenti dalla chiave, quindi non c'è ambiguità. GROUP BY u.id consente legittimamente SELECT u.name, u.email, ....
Cause comuni
- Aggiungere una colonna alla SELECT di una query raggruppata esistente senza pensare a quale valore del gruppo dovrebbe portare.
- Portare query da MySQL, dove storicamente questo "funzionava".
- Volere qualcosa che GROUP BY non esprime: "la riga più recente / top per gruppo" — una forma di query del tutto diversa (sotto).
Come diagnosticarlo
Per la colonna segnalata, rispondi a una domanda: quale valore di riga voglio davvero? "Uno qualsiasi, sono tutti uguali" → raggruppa per la chiave che lo rende tale (o la PK). "Il max/min/sum" → aggrega. "Quello della riga più recente" → vuoi DISTINCT ON, non GROUP BY.
Come risolverlo
-- 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 aggiunge anche any_value() per il caso genuino "uno qualsiasi va bene".
