ROW_NUMBER()必须配合OVER()使用,否则报错;它是窗口函数,需指定ORDER BY排序逻辑,且不能在WHERE中直接引用其别名,正确用法是子查询或CTE。

ROW_NUMBER() 必须配合 OVER() 使用,否则直接报错
不写 OVER(),ROW_NUMBER() 就不是函数,而是语法错误。MySQL 8.0+、PostgreSQL、SQL Server、Oracle 都一样,没得商量。
常见错误现象:ERROR: window function ROW_NUMBER requires an OVER clause(PostgreSQL)或类似提示。
-
ROW_NUMBER()是窗口函数,不是普通标量函数,它必须知道“按什么排序、在哪个范围内编号” - 最简合法写法是
ROW_NUMBER() OVER (ORDER BY id),哪怕你只是想按插入顺序编号,也得选一个列来ORDER BY - 如果表没主键、没时间戳、也没明显排序依据,硬凑
ORDER BY (SELECT NULL)在某些数据库(如 SQL Server)能跑,但 PostgreSQL 不允许;更稳妥的是加个ctid(PostgreSQL)或%%physloc%%(SQL Server),不过这些属于实现细节,不可移植
ORDER BY 在 OVER() 里决定行号顺序,不是查询末尾的 ORDER BY
很多人以为写个 ORDER BY id DESC 在 SQL 最后就能控制行号顺序——不行。ROW_NUMBER() 的排序只认 OVER() 里的 ORDER BY,外面那个只影响最终结果集显示顺序,不改变行号生成逻辑。
使用场景:比如取每个用户最新一条订单,就得用 ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY created_at DESC),然后外层 WHERE rn = 1。
- 如果
OVER()里没写ORDER BY,多数数据库直接报错;少数(如旧版 MySQL)可能允许但行为未定义 -
PARTITION BY是可选的,但一旦用了,ORDER BY仍必须存在,且作用域是每个分区内独立编号 - 性能上,
ORDER BY列最好有索引,尤其当数据量大时,否则窗口函数会触发全局排序,很慢
ROW_NUMBER() 和 RANK()、DENSE_RANK() 的区别不只是“并列怎么算”
三者都生成序号,但语义不同:ROW_NUMBER() 强制唯一、严格递增;RANK() 并列时跳号;DENSE_RANK() 并列时不跳号。选错会导致业务逻辑出错,比如分页取第 2 页(rn BETWEEN 11 AND 20)时,用 RANK() 可能实际只返回 15 行。
容易踩的坑:
- 误以为
ROW_NUMBER()能“去重”——它不判断值是否重复,只按排序位置给号。两行完全相同的数据,只要排序列值一样,ROW_NUMBER()也会给出不同编号 - 在需要稳定分页(例如前端无限滚动)时,
ORDER BY列必须包含唯一键(如ORDER BY status, id),否则同一批数据多次执行可能因排序不稳定导致行号漂移 - MySQL 8.0 前没有窗口函数,有人用变量模拟
@row := @row + 1,但那种写法在复杂查询中极易出错,且不保证执行顺序,现在没必要这么干了
别在 WHERE 里直接引用 ROW_NUMBER() 别名
SELECT *, ROW_NUMBER() OVER (ORDER BY id) AS rn FROM t WHERE rn > 10 这种写法一定报错:rn 是 SELECT 投影阶段才产生的别名,WHERE 执行在前,看不到它。
正确做法只有两种:
- 套一层子查询:
SELECT * FROM (SELECT *, ROW_NUMBER() OVER (ORDER BY id) AS rn FROM t) t2 WHERE rn BETWEEN 11 AND 20 - 用 CTE:
WITH numbered AS (SELECT *, ROW_NUMBER() OVER (ORDER BY id) AS rn FROM t) SELECT * FROM numbered WHERE rn > 10 - 注意:CTE 不是所有数据库都支持(比如 SQLite 3.8.3 前不支持),而子查询是通用解法
这个限制背后是 SQL 执行顺序:FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY → LIMIT。窗口函数在 SELECT 阶段计算,WHERE 阶段根本还没轮到它。
复杂点在于,一旦加上 PARTITION BY,子查询嵌套层级容易变深,别为了省一行代码把逻辑揉进单条语句里——可读性和调试成本会陡增。










