Can ORDER BY sort by an expression or by a select-list position such as ORDER BY 2?
answer
- Sort keys are not limited to columns
- A key can be computed and never returned
- An integer literal means something special
- It counts select-list columns from one
- Editing the SELECT list silently re-points it
basics
~20 sYes to both. ORDER BY accepts any expression over the row, including one the query does not return, and an integer literal that refers to the nth column of the select list. Ordinals are brittle: editing the SELECT list silently changes the sort.
solid answer
~50 sA sort key does not have to be a plain column. It can be any expression built from the row's columns — `ORDER BY CHAR_LENGTH(title) DESC`, `ORDER BY unit_price * quantity` — and that expression need not appear in the SELECT list, because the engine can evaluate it for ordering and then discard it. An integer literal is treated specially: `ORDER BY 2` means "the second column of the select list", not the constant two. That shorthand is convenient in ad-hoc queries but dangerous in stored code, because inserting a column into the SELECT list re-points every ordinal without any error. Two caveats: under `SELECT DISTINCT` a sort key must be something the select list actually produces, since rows are deduplicated before ordering; and any literal you write that is *not* an integer, such as `ORDER BY 'name'`, is a constant, so it orders nothing.
code
sql · 8 lines-- The sort key need not appear in the result
SELECT product_name
FROM products
ORDER BY unit_price * stock_quantity DESC;
-- Text that holds numbers sorts lexicographically: '10' before '9'
SELECT version_text FROM releases ORDER BY version_text;
SELECT version_text FROM releases ORDER BY CAST(version_text AS INTEGER);go deeper
Know that ORDER BY can take an expression, and that a bare integer refers to a select-list column by position rather than to the number itself.
Explain why a sort key need not be selected, why SELECT DISTINCT is the exception, and why a text column of numbers needs a CAST in the sort key to order correctly.
Argue the maintenance case against ordinals in stored queries — a select-list edit re-points them with no error — and show the alias or expression rewrite you would require in review.
Set the convention for generated and templated SQL: how sort keys arrive from user input, why they are validated against a fixed list of columns, and why ordinals are banned from anything version-controlled.
## Three shapes a sort key can take ORDER BY accepts more than bare column names. In practice you will see three forms: 1. **A column reference** — `ORDER BY created_at`. 2. **An expression** — `ORDER BY CHAR_LENGTH(title) DESC`, `ORDER BY unit_price * quantity DESC`, `ORDER BY CAST(version_text AS INTEGER)`. 3. **An ordinal position** — `ORDER BY 2`, meaning the second item of the select list. All three can be mixed in one list and each takes its own ASC/DESC. ## Sorting by an expression you do not return Because ordering happens over the rows the query has already produced, the engine can compute a sort key that never reaches the client: ```sql SELECT product_name FROM products ORDER BY unit_price * stock_quantity DESC; ``` The result has one column, but the rows come back in inventory-value order. This is genuinely useful: the sort criterion is often a derived quantity the consumer does not need to see. The exception is `SELECT DISTINCT`. Duplicate elimination collapses rows before ordering, so a sort key that is not part of the returned row is ambiguous — the surviving row would have several possible values for it — and the standard requires ORDER BY items to be select-list items in that case. `SELECT DISTINCT city FROM users ORDER BY created_at` is not well-defined and engines reject it. ## Expressions that fix a wrong-looking sort A common interview follow-up is the column of numbers stored as text. `ORDER BY version_text` sorts lexicographically, so `'10'` lands before `'9'` — string comparison examines characters left to right and `'1'` precedes `'9'`. The fix is an expression key: ```sql ORDER BY CAST(version_text AS INTEGER); ``` The same shape solves date-as-text columns and mixed-case sorting. The point is that the *type of the sort key expression*, not the type of the stored column, decides how values are compared. ## Ordinal positions: what the integer means An unadorned integer in ORDER BY is not a value to sort by — it is a reference to the select list by position, counting from 1: ```sql SELECT category, SUM(amount) AS total FROM sales GROUP BY category ORDER BY 2 DESC; -- by total, descending ``` That is why `ORDER BY 2` is not the same as `ORDER BY 'a constant'`: a non-integer literal is just a constant expression with the same value in every row, so it imposes no ordering at all — a silent no-op that occasionally shows up in generated SQL. Ordinals are widely accepted and handy at a prompt, especially for sorting by an aggregate or a long expression you do not want to retype. In code that lives, they are a liability: adding one column to the front of the select list shifts every position, the query still parses, and the output is quietly sorted by the wrong thing. Prefer naming the column or repeating the expression. ## Aliases as sort keys You can also sort by a column alias defined in the select list — `SELECT SUM(amount) AS total ... ORDER BY total DESC` — because ORDER BY is the one clause positioned after the select list is computed. Watch for a name collision: if the alias reuses a base-table column name, an unqualified reference in ORDER BY is ambiguous between the output column and the underlying column, and engines resolve that differently. Avoid the collision rather than memorise the resolution rules. ## Combining forms Nothing stops you mixing them, though readability suffers: ```sql SELECT customer_id, COUNT(*) AS order_count, MAX(placed_at) AS last_order FROM orders GROUP BY customer_id ORDER BY order_count DESC, last_order DESC, customer_id; ``` Here two aliases and one column carry the ordering. The same query written `ORDER BY 2 DESC, 3 DESC, 1` behaves identically and reads far worse. ## Practical guidance - Use expressions freely as sort keys; they do not have to be selected (except under DISTINCT). - Reach for CAST when a text column needs numeric or chronological ordering. - Treat ordinals as an interactive convenience only, never in views, reports or application code. - Remember that a non-integer literal sort key sorts nothing. - Do not let a select-list alias shadow a base column name you also sort by.
- What does ORDER BY 'created_at' — with quotes around it — do?Nothing useful. A quoted string is a character literal, so every row gets the same sort-key value and no ordering is imposed; the rows come back in an unspecified order. Only an *integer* literal is interpreted as a select-list position. This is a real bug in generated SQL where a column name is interpolated as a string instead of an identifier.
- Why does SELECT DISTINCT restrict which expressions ORDER BY may use?Duplicate elimination happens before ordering, so a surviving row no longer corresponds to a single source row. A sort key that is not in the select list could take several values for that one output row, leaving the order undefined. The standard therefore requires ORDER BY items under DISTINCT to be select-list items.
- A VARCHAR column holding dates as 'DD/MM/YYYY' sorts wrongly. What is the ORDER BY fix?Sort by an expression that produces a real date, for example `ORDER BY CAST(...)` after rearranging the parts, rather than by the raw string — text comparison reads left to right, so day-first strings order by day. The durable fix is a DATE column; the ORDER BY expression is the workaround while the schema still stores text.
saying these in an interview costs you the question
- Thinks ORDER BY 2 sorts by the constant two
- Believes sort keys must appear in SELECT
- Uses ordinal positions in production views
- Assumes numeric text sorts numerically
- Says expressions are not allowed in ORDER BY