Can GROUP BY reference a SELECT-list alias or an ordinal position?
answer
- Which clause is computed first?
- The output name does not exist yet
- ORDER BY is allowed what GROUP BY is not
- Repeat the expression, or wrap in a derived table
basics
~20 sStandard SQL says no: GROUP BY is evaluated before the select list is projected, so output aliases do not exist yet and you must repeat the expression. Several engines allow aliases or ordinals as an extension.
solid answer
~40 sPer the standard, `GROUP BY` takes input-column references and expressions, not select-list aliases or ordinal positions — grouping happens **before** the select list is projected, so the output name does not exist yet. The portable form repeats the expression verbatim: `GROUP BY EXTRACT(YEAR FROM order_date)`, matching what the select list computes. Engines add extensions: PostgreSQL accepts an output-column name and an ordinal number in `GROUP BY`, MySQL accepts an alias, and SQL Server accepts neither and requires the full expression. Two portable ways to avoid the repetition are to compute the expression in a derived table or CTE and group by its column name in the outer query. Note that `ORDER BY` is different — the standard *does* allow aliases and ordinals there, because sorting happens after projection.
code
sql · 5 lines-- Portable: repeat the expression; the alias is legal only in ORDER BY
SELECT EXTRACT(YEAR FROM order_date) AS order_year, COUNT(*) AS orders
FROM orders
GROUP BY EXTRACT(YEAR FROM order_date)
ORDER BY order_year;go deeper
Know the safe habit: write the expression itself in GROUP BY, and save the alias for ORDER BY, where the standard allows it.
Explain it from the evaluation order — grouping runs before projection, so the alias does not exist yet — and show the derived-table rewrite that names the expression once.
Bring the portability call: alias and ordinal support varies by engine, ordinals are positionally fragile, and a CTE removes the duplicated expression without relying on any extension.
Set the convention for the codebase: no ordinals in committed SQL, expressions named once in a CTE, so a select-list edit can never silently change the grouping key.
## Why the question comes up A grouped query on a derived value forces you to write the expression twice: ```sql SELECT EXTRACT(YEAR FROM order_date) AS order_year, COUNT(*) AS orders FROM orders GROUP BY EXTRACT(YEAR FROM order_date) ORDER BY order_year; ``` The duplication is annoying and a maintenance hazard — change one copy and the other silently produces a different grouping, or the query fails the every-selected-column check because the two expressions no longer match. The natural instinct is `GROUP BY order_year` or `GROUP BY 1`. ## What the standard permits The logical evaluation order places `GROUP BY` before the select list is computed. At grouping time the query is still working with the input columns of the `FROM` clause; `order_year` is a name that will exist only in the result. So standard `GROUP BY` takes column references and expressions over input columns — no output aliases, and no ordinal positions. `ORDER BY` is the deliberate contrast. Sorting is applied to the finished result, after projection, and the standard explicitly permits both a select-list alias and an ordinal position there. That asymmetry — `ORDER BY order_year` legal, `GROUP BY order_year` not — is the whole point of the question, and it follows from *when* each clause is evaluated rather than from any arbitrary rule. ## What engines actually accept Extensions are common, which is why candidates disagree about the answer: - **PostgreSQL** documents that a `GROUP BY` item may be an input-column name, or the name or ordinal number of an output column; when a name is ambiguous it resolves to the input column. - **MySQL** accepts a select-list alias in `GROUP BY`. - **SQL Server** accepts neither an alias nor an ordinal in `GROUP BY`; you must write the expression. Because the behaviour differs, a query using the alias form is not portable, and one using ordinals has a second problem: `GROUP BY 1, 2` is positional, so reordering or inserting a select-list column silently changes the grouping without any error. Ordinals in `GROUP BY` are best treated as an interactive-analysis convenience, not something you commit. ## Portable ways to avoid writing the expression twice Compute the expression once in an inner query block and group by its name in the outer one. A derived table: ```sql SELECT order_year, COUNT(*) AS orders FROM (SELECT EXTRACT(YEAR FROM order_date) AS order_year FROM orders) t GROUP BY order_year ORDER BY order_year; ``` or the same thing in a `WITH` clause. In the outer block `order_year` is a genuine input column of the derived table, so the reference is standard, no alias extension is involved, and the expression exists in exactly one place. This also satisfies the every-selected-column rule cleanly: the select list projects `order_year`, and `order_year` is the grouping column. ## Matching expressions, not just names One more trap lives here. When you do repeat the expression, engines compare it structurally against the select-list item. `GROUP BY EXTRACT(YEAR FROM order_date)` licenses selecting exactly that expression. Selecting `EXTRACT(YEAR FROM order_date) + 0`, or a differently-cast variant, is a *different* expression and can be rejected as not a grouping expression even though it is deterministic in the group. Keep the two copies textually identical, or move to the derived-table form where the question cannot arise. ## How to answer in an interview Lead with the reason, not the verdict: grouping precedes projection, so the alias does not yet exist; that is why the standard requires the expression and why `ORDER BY` — which runs after projection — is allowed the alias. Then note that several engines relax it, that ordinals are positional and fragile, and that the derived table or CTE is the portable way to write the expression once. That sequence shows you understand the evaluation model rather than having memorized which database tolerates what.
- Why does ORDER BY accept an alias when GROUP BY does not?Because of when each clause is evaluated. Grouping happens before the select list is projected, so output names do not exist yet; sorting is applied to the already-projected result, where the alias is a real column name. The standard reflects that ordering, and it also permits ordinal positions in ORDER BY.
- What is the risk of writing GROUP BY 1, 2 even on an engine that accepts it?It is positional, so inserting or reordering a select-list column silently regroups the data with no error and no obvious diff. It is acceptable for throwaway interactive queries; in committed code, name the expression — ideally once, in a derived table or CTE.
- If the select list computes a slightly different expression than GROUP BY, what happens?Engines match grouping expressions structurally, so a variant such as an extra cast or arithmetic is a different expression and can be rejected as not a grouping expression. Keep both copies textually identical, or eliminate the duplication with a derived table.
saying these in an interview costs you the question
- Says GROUP BY and ORDER BY follow the same alias rules
- Assumes ordinals in GROUP BY are standard SQL
- Commits GROUP BY 1, 2 to production code
- Thinks any equivalent expression satisfies the grouping check
- Believes repeating the expression evaluates it twice as a semantic difference