ROW_NUMBER() assigns a unique, sequential integer to every row within
its window, starting at 1. Ties in the ORDER BY are broken arbitrarily —
no two rows ever receive the same number.
Ordered values: [10, 20, 20, 40]
ROW_NUMBER(): [1, 2, 3, 4]
ROW_NUMBER() never produces duplicate values, even on ties.ROW_NUMBER() inside a CTE/subquery to filter on it (since window
function results cannot be referenced directly in WHERE).SELECT statementsORDER BYWITH clause) — module 06_CTEsSELECT
column_a,
column_b,
ROW_NUMBER() OVER (ORDER BY sort_column) AS row_seq
FROM table_name;
employes (emp_id, emp_name, dept_id, manager_id)
See 01_row_number.sql for five fully worked,
production-commented examples.
ROW_NUMBER() = 1 per group).| Domain | Scenario |
|---|---|
| HR | Assign a unique seniority sequence to employees |
| E-commerce | Number a customer’s orders chronologically |
| Banking | Sequence transactions for a statement |
ROW_NUMBER() alias directly in a WHERE clause on the
same SELECT — this throws a syntax/semantic error because WHERE runs
before window functions are evaluated. Always wrap in a CTE or subquery.ORDER BY inside OVER(), which makes the numbering
non-deterministic.ROW_NUMBER() respects ties like RANK() does — it does not.emp_seq, not rn).ROW_NUMBER() over LIMIT alone when you need deterministic,
per-group “top-N” results (combine with PARTITION BY).ROW_NUMBER() is computed by MySQL’s window function engine in a single
pass after the base result set is materialized. It is O(n log n) due to the
required sort on ORDER BY. For very large tables, ensure the ORDER BY
column is indexed to avoid an expensive filesort.
emp_id.emp_name instead.ROW_NUMBER().ROW_NUMBER() = 1 (requires a CTE or subquery).Beginner
20–25 minutes
ROW_NUMBER() OVER (ORDER BY ...).WHERE, and how to solve that with a CTE.← Previous: Module README
↑ Module README
→ Next: 02_RANK