PostgreSQL-Fehler: 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 einer gruppierten Query muss jede selektierte Spalte entweder Teil des Gruppenschlüssels oder in ein Aggregat eingehüllt sein — andernfalls gibt es viele Kandidatenwerte pro Gruppe und keine Regel, um einen auszuwählen. Datenbanken, die "hilfsbereit" trotzdem einen auswählen (wie es ältere MySQL tat), liefern nichtdeterministische Daten; PostgreSQL verweigert.

Was dieser Fehler bedeutet

Jede Ergebniszeile einer GROUP BY-Query repräsentiert viele Quellzeilen. department ist in Ordnung (es definiert die Gruppe), count(*) ist in Ordnung (es aggregiert die Gruppe) — aber name? Welcher der 40 Mitarbeiter der Abteilung soll ihn liefern? Die Query ist wirklich mehrdeutig, und der Fehler ist die Antwort des SQL-Standards.

Eine dokumentierte Ausnahme: gruppieren Sie nach dem Primärschlüssel einer Tabelle, und Sie dürfen jede Spalte dieser Tabelle selektieren — sie sind funktional vom Schlüssel abhängig, es gibt also keine Mehrdeutigkeit. GROUP BY u.id erlaubt legitim SELECT u.name, u.email, ....

Häufige Ursachen

So diagnostizieren Sie ihn

Beantworten Sie für die markierte Spalte eine Frage: welchen Zeilenwert will ich eigentlich? "Egal, sie sind alle gleich" → gruppieren Sie nach dem Schlüssel, der das so macht (oder dem PK). "Das Max/Min/Summe" → aggregieren. "Der aus der neuesten Zeile" → Sie wollen DISTINCT ON, nicht GROUP BY.

So beheben Sie ihn

-- Der Wert wird durch die Gruppe bestimmt → nach dem Schlüssel gruppieren:
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 ist erlaubt

-- Sie wollen ein Aggregat davon:
SELECT department, count(*), max(salary) FROM employees GROUP BY department;

-- Sie wollen "die neueste Zeile pro Gruppe" → DISTINCT ON:
SELECT DISTINCT ON (customer_id) *
FROM orders
ORDER BY customer_id, created_at DESC;

PostgreSQL 16 fügt außerdem any_value() für den echten "irgendeine tut's"-Fall hinzu.

🔍 Dieselbe Mehrdeutigkeit in einem anderen Kostüm: more than one row returned by a subquery.