skip to content

What does ORDER BY resolve to when a SELECT alias reuses an existing column's name?

level: seniorimportance: nice to knowfreq 26%

answer

  1. the same name, two clauses, two meanings
  2. output names exist only at the end
  3. bare versus qualified changes the answer
  4. an output column cannot be qualified
  5. best fix is a name that does not collide

basics

~20 s

A bare name in ORDER BY resolves to the select-list alias first, while WHERE and GROUP BY see only input columns, so one identifier can mean two different things in a single statement. Qualify the base column, or do not reuse the name.

solid answer

~50 s

When a select-list alias shadows a column of an underlying table, the same identifier means different things in different clauses. `ORDER BY` is resolved over the result columns, so a **bare** name that matches an output column resolves to the alias — PostgreSQL and MySQL both document that output names are searched first. `WHERE` and `GROUP BY` are resolved before the select list exists, so the identifier there can only be the input column. The escape hatch is qualification: an output column name cannot be qualified, so `ORDER BY l.amount` unambiguously means the table's column, while `ORDER BY amount` means the alias. The result is a query that filters on one value and sorts by another without any error being raised — which is why the practical rule is simply not to alias an expression with the name of a column already in scope.

code

sql · 9 lines
sql
-- The alias shadows the base column: the sort uses the negated value
SELECT -amount AS amount
FROM ledger
ORDER BY amount;

-- A qualified reference can only mean the input column
SELECT -amount AS amount
FROM ledger AS l
ORDER BY l.amount;

go deeper

for a junior

The takeaway is a habit: do not give an alias the same name as a column that already exists in the query's tables, because references elsewhere in the statement become hard to read.

for a middle

Explain that ORDER BY resolves a bare name against the result's output columns first, while WHERE and GROUP BY can only see input columns, so one identifier can carry two meanings in a single statement.

for a senior

Be ready to diagnose it: a report that filters correctly but sorts by the wrong values, with no error anywhere. Show the qualified-reference test that proves which namespace won, and argue for renaming rather than relying on the rule.

for a principal

The angle to own is reviewability. A construct that is legal, silent and dependent on per-clause name resolution is a maintenance liability, so decide as a team that aliases never shadow columns and let linting or review carry it.

## The shape of the trap ```sql SELECT -amount AS amount FROM ledger WHERE amount > 0 ORDER BY amount; ``` This statement runs. It filters rows whose **stored** `amount` is positive, and sorts by the **negated** value. One identifier, two meanings, no error. That is the shadowing hazard this leaf is about, and it is why reviewers flag aliases that reuse a base column's name. ## The resolution rules, clause by clause - `WHERE`, `GROUP BY`, `HAVING` are resolved before the select list produces output names, so an identifier there can only be an **input column** — a column of a table in `FROM`. - `ORDER BY` is resolved last, over the finished result. A **bare** identifier that matches an output column name resolves to that output column. PostgreSQL documents this explicitly: when a simple name matches both an output column and an input column, `ORDER BY` interprets it as the output column. MySQL documents the same search order — select-list expressions first, then columns of the tables in `FROM`. - A **compound expression** in `ORDER BY` — anything more than a bare name, such as `UPPER(amount)` or `amount + 0` — is built from input columns, because output names are not values you can compute over. So `ORDER BY amount` and `ORDER BY amount + 0` can sort by different things in the same query. That is not a bug in any engine; it falls out of what an output name is. ## Qualification disambiguates, in one direction An output column name has no table to belong to — it exists only in the result — so it can never be qualified. That gives a precise tool: ```sql SELECT -amount AS amount FROM ledger AS l ORDER BY l.amount; -- unambiguously the table's column ``` `l.amount` must be the input column. There is no corresponding syntax to force the alias, other than writing the bare name (or, in engines that support it, the select-list ordinal). So: qualify when you mean the column; leave it bare when you mean the alias; and prefer never to need the distinction. ## Why the language allows the shadowing at all Because aliases are how you *rename* things, and renaming to the same name is a legitimate operation. `SELECT COALESCE(nickname, name) AS name` is idiomatic — the caller wants a column called `name`, and the query author is providing one. Nothing is wrong with the alias; the hazard is only that a later clause in the *same* statement may then refer to the identifier and get a different answer than the author expected. ## A related restriction worth knowing When a query uses `SELECT DISTINCT`, `ORDER BY` may reference only expressions that appear in the select list, because sorting by something not present in the deduplicated result is not well defined. In such a query the shadowing question disappears: only output columns are addressable. ## Diagnosing it in the wild The symptom is a report that filters correctly but sorts wrongly, or a top-N list whose ordering does not match the column it appears to be sorted on. Nothing errors and nothing logs. Three checks find it quickly: 1. Look for an `AS` in the select list whose name also exists in one of the tables in `FROM`. 2. Rewrite the `ORDER BY` reference with the table alias and see whether the ordering changes; if it does, the query was sorting by the alias. 3. Rename the alias to something unique and re-run — if the sort changes, the alias was shadowing. ## The rule to state in review "An alias may reuse a column's name only when the statement never references that name again." In practice, that means: shadowing a name in a final projection is fine; shadowing it in a query that also sorts, groups or filters on the name is a defect, because a maintainer will read the identifier once and assume it means one thing in every clause. Where the shadow is genuinely wanted — the `COALESCE(nickname, name) AS name` case — compute it in a CTE and let the outer query sort on the unambiguous result. ## What interviewers listen for They want to hear that resolution depends on the clause, that `ORDER BY` prefers output names for bare identifiers while `WHERE` and `GROUP BY` see only input columns, and that a qualified reference is always an input column. The senior signal is the conclusion drawn from it: the rule exists, you should know it, and you should still write queries that never require the reader to know it.

  • How do you make the intent explicit without relying on the resolution rule?
    Qualify with the table alias when you mean the stored column (`ORDER BY l.amount`), since output names can never be qualified. Better still, give the alias a name that collides with nothing — `net_amount` instead of `amount` — so no reader has to know which clause searches which namespace.
  • Does WHERE resolve the identifier the same way ORDER BY does?
    No. `WHERE` is resolved before the select list exists, so the identifier there can only be an input column; the alias is not visible to it at all. That is exactly why the two clauses can disagree: `WHERE amount > 0` filters the stored column while `ORDER BY amount` sorts the aliased expression.
  • Can you force ORDER BY to use the output column when a same-named input column exists?
    Write the bare name — that is already the output-first case — or, where the engine supports ordinals, reference the select-list position. There is no qualified syntax for an output name, because it belongs to the result rather than to any table, so the bare form is the only explicit handle.
  • Is aliasing an expression with an existing column's name ever legitimate?
    Yes, in a final projection: `SELECT COALESCE(nickname, name) AS name` deliberately hands the caller a column called `name`. It is safe precisely because nothing else in that statement refers to the identifier. Compute it in a CTE if the outer query then needs to sort or group on the result.

saying these in an interview costs you the question

  • Assumes an identifier means the same thing in every clause
  • Thinks ORDER BY always sorts by the underlying stored column
  • Says shadowing is impossible because aliases exist only at the end
  • Believes qualifying with the table alias selects the select-list alias
  • Dismisses the difference as undefined engine behaviour

context