row_number()必须配合over子句使用,否则报错;基本形式为row_number() over (order by column),分组需加partition by,且order by不可省略以确保排序稳定性和编号唯一性。

ROW_NUMBER() 必须配合 OVER 子句使用,否则报错
直接写 SELECT ROW_NUMBER() 会触发语法错误,因为这个函数是窗口函数,没有 OVER 就不知道按什么排序、分什么组。常见错误信息是:ERROR: window function ROW_NUMBER requires an OVER clause。必须明确指定排序逻辑,哪怕只是按某个字段升序——哪怕业务上不关心顺序,也得写个兜底的 ORDER BY id 或 ORDER BY 1(按第一列)。
实操建议:
-
OVER (ORDER BY created_at DESC):按时间倒序编号,最新记录为 1 -
OVER (ORDER BY user_id, order_date):多字段排序,避免相同值导致编号“不稳定” - 慎用
ORDER BY NULL或ORDER BY RANDOM():前者在某些数据库(如 PostgreSQL)不被允许;后者性能差,且每次执行结果不同,不适合分页或导出
分区编号(PARTITION BY)和全局编号的区别很关键
不加 PARTITION BY 是对整个结果集从 1 开始连续编号;加上之后,会在每个分组内重新从 1 编号。比如统计每个用户的订单序号,就得用 PARTITION BY user_id ORDER BY order_date。
容易踩的坑:
- 误把
PARTITION BY当成GROUP BY:它不聚合数据,只是划分编号范围,原始行数不变 - 分区字段有 NULL 值时,所有 NULL 会被归为同一组(PostgreSQL/SQL Server 行为),可能造成意外合并
- MySQL 8.0+ 支持,但 MySQL 5.7 及更早版本不支持窗口函数,会直接报错
FUNCTION xxx.ROW_NUMBER does not exist
ROW_NUMBER() 和 RANK()、DENSE_RANK() 的编号逻辑差异
三者都依赖 OVER,但处理并列情况的方式完全不同。例如两行并列第 2 名:
-
ROW_NUMBER():强制给唯一序号 → 1, 2, 3(即使值相同) -
RANK():跳号 → 1, 2, 2, 4(两个第 2 名后直接第 4 名) -
DENSE_RANK():不跳号 → 1, 2, 2, 3(两个第 2 名后是第 3 名)
选哪个取决于业务语义。做“取每个部门薪资最高的前 3 人”,用 ROW_NUMBER() 能确保最多 3 条;用 RANK() 可能返回 4 条或更多(如果第 3 名并列)。
在 WHERE 或 JOIN 中不能直接引用 ROW_NUMBER() 别名
下面这句会报错:SELECT *, ROW_NUMBER() OVER (ORDER BY score) AS rn FROM students WHERE rn 。因为 SQL 执行顺序中,<code>WHERE 在窗口函数计算之前运行,此时 rn 还不存在。
正确做法只有两种:
- 用子查询或 CTE 包一层:
WITH ranked AS (SELECT *, ROW_NUMBER() OVER (...) AS rn FROM t) SELECT * FROM ranked WHERE rn - 在支持的数据库中(如 PostgreSQL、SQL Server),可用
LATERAL或派生表,但本质仍是延迟过滤时机
别指望在 ON 条件或 HAVING 里直接用它——窗口函数的计算时机是固定的,绕不开。
真正麻烦的地方在于:很多人想靠 ROW_NUMBER() 实现分页,却忘了它本身不加速查询;如果底层数据没索引支撑 ORDER BY 字段,性能会断崖式下降。










