Why SQL Says a Column Must Appear in the GROUP BY Clause
Fix the GROUP BY "column must appear" error, understand why it fires, and see why MySQL's silent version of the same bug is worse than an error.
The query that won't run
You add one column to a SELECT that already has a GROUP BY, and the
database refuses to run it:
column "first_name" must appear in the GROUP BY clause or be used in an
aggregate function
Nothing about the query looks wrong. It is a column that genuinely exists,
on a table you're already querying. The rule causing this: every column in
SELECT must either be listed in GROUP BY, or be wrapped in an aggregate
function like COUNT, SUM, or AVG. If it's neither, the database has no
single value to return for it, because GROUP BY has already collapsed many
rows into one.
Run the broken version yourself:
Five departments, but the query asks for first_name per department, and a
department has several employees, each with a different first name. There is
no single first name to put in that cell, so the engine won't guess. That's
the whole error: not a typo, not a missing join, just an unanswerable
question.
The real fix: decide what "one row per group" means
The fix isn't to satisfy the parser, it's to decide what a department's row should actually contain. If you want a per-department summary, aggregate the columns that vary within the group:
Now every column has an unambiguous value per group: department_id is the
group itself, headcount and avg_salary are aggregates computed across the
rows in it. That is the pattern: group by the thing you are summarizing
over, aggregate everything else.
The "fix" that makes the error go away and the query useless
The error message makes people reach for the wrong fix: throw every selected
column into GROUP BY until it compiles. It works, syntactically:
Twenty rows. Compare that to a plain count of the table:
Also twenty. GROUP BY on every selected column groups each row with
itself, because the combination of department, name, and salary is already
unique per employee, so nothing actually got summarized. The query stopped
erroring and started lying instead: it looks like a grouped report, but it's
the raw table with extra syntax. If your goal was one row per department,
this "fix" didn't get you there; it just hid the fact that you hadn't
decided what to aggregate.
A query that runs is not a query that's right
GROUP BY accepting your columns only proves the syntax is legal. It says
nothing about whether the result still answers your original question.
Check the row count against what you expected before trusting the output.
Grouping through a join
The same rule applies once a join is involved, and it's where the error catches people who thought they'd already fixed it. Say you want headcount and average salary per department, but by name instead of ID:
d.name is grouped, e.salary is aggregated, so every selected column is
accounted for, same as before, just spread across two tables. The rule
doesn't care which table a column comes from, only whether it's grouped or
aggregated.
To filter on the aggregate itself, say departments averaging over
$100,000, WHERE will not work, because WHERE runs before the grouping exists.
That's HAVING's job, and it's a big enough topic on its own; see
GROUP BY with HAVING for a full walkthrough.
Here it's one clause added to what you already have:
Engineering is the only department clearing six figures on average.
The version of this bug that doesn't error
Every guide that covers this error frames it as a parser complaint you fix and move past. That's true on PostgreSQL, SQL Server, and DuckDB (which is what runs the examples on this page). They all enforce the rule strictly. It is not true everywhere.
MySQL can run the invalid query and answer wrong
Older MySQL, and any MySQL or MariaDB instance with ONLY_FULL_GROUP_BY
turned off, will execute a query like the broken one at the top of this
page without complaint. It doesn't average the ungrouped column or reject
it. It picks one row's value per group, arbitrarily, and that choice can
change between runs. ONLY_FULL_GROUP_BY has been the default since MySQL
5.7.5, but a lot of production databases still run with it disabled,
often because someone hit this exact error years ago and turned the check
off instead of fixing the query.
That's the trap: disabling the check doesn't fix anything, it just converts
a loud compile-time error into a silent data-correctness bug. The query
still does not know which first name belongs in a five-person department;
it just stops telling you that and picks one anyway. If a report's numbers
are technically valid but the names next to them look randomly assigned,
this is usually why. The fix is the same fix as above: aggregate the column
or add it to GROUP BY, and ONLY_FULL_GROUP_BY should stay on, not off.
Where to practice this
GROUP BY and its error modes come up constantly once joins and aggregates
mix. /learn/group-by covers the clause from first
principles if any part of this felt shaky, and the
practice problems have several grouping exercises where you
can trigger this error yourself and fix it under different constraints
before it shows up in a real query.
Cite this resource
SQLSimplified. "Why SQL Says a Column Must Appear in the GROUP BY Clause". Available at: https://sqlsimplified.online/blog/column-must-appear-in-group-by-clause