ROW_NUMBER() 必须配合 OVER 子句使用,是窗口函数而非普通函数;最简形式为 ROW_NUMBER() OVER (ORDER BY some_column),需指定排序以保证结果稳定;支持 PARTITION BY 实现分组内独立编号;末尾 ORDER BY 仅控制输出顺序,不改变行号逻辑;大偏移分页性能差,应优先用原生分页语法。

ROW_NUMBER() 必须配合 OVER 子句使用,否则报错
直接写 SELECT ROW_NUMBER() 会触发类似 Window function 'ROW_NUMBER' requires an OVER clause 的错误。它不是普通函数,而是窗口函数,必须明确指定排序逻辑和分区范围。
最简可用形式是:ROW_NUMBER() OVER (ORDER BY some_column)。哪怕只是想按自然顺序编号,也得选一个列(比如主键)来保证结果稳定——没有 ORDER BY,行号顺序不可预测,不同执行可能得到不同编号。
- 不能写成
ROW_NUMBER()单独出现 -
OVER ()空括号不合法 - 如果表无主键或唯一排序依据,用
ORDER BY (SELECT NULL)虽能通过语法检查,但实际行为依赖引擎实现,不推荐
给分组内数据单独编号要用 PARTITION BY
比如查每个部门员工薪资排名,需要“部门内从1开始编号”,这时靠 ORDER BY 不够,必须加 PARTITION BY dept_id。
示例:ROW_NUMBER() OVER (PARTITION BY dept_id ORDER BY salary DESC)。注意 PARTITION BY 在 ORDER BY 前,且两者都在 OVER 内部。
-
PARTITION BY字段值相等的行会被归为一组,每组独立编号 - 组内编号始终从 1 开始,不会延续到下一组
- 若漏掉
ORDER BY,即使有PARTITION BY,仍会报错
ORDER BY 在查询末尾会影响 ROW_NUMBER 的结果
SQL 执行顺序中,SELECT 子句(含 ROW_NUMBER())在 ORDER BY 之前计算。所以最终结果集的物理顺序,由查询末尾的 ORDER BY 决定,而不是 OVER 里的 ORDER BY。
这意味着:如果 OVER 里按 name 排,但查询末尾又写 ORDER BY id,那么行号仍是按 name 算出来的,但显示顺序按 id 排——行号和视觉顺序可能不一致。
- 行号逻辑只取决于
OVER中的ORDER BY - 末尾
ORDER BY只控制最终输出顺序,不改变已生成的行号值 - 调试时建议先去掉末尾
ORDER BY,确认行号是否符合预期
性能敏感场景下慎用大偏移量的 ROW_NUMBER
当需要取第 100001 行(比如分页跳转到第 10001 页,每页 10 条),ROW_NUMBER() 仍需对全量数据排序并编号到 100001,再过滤。相比 LIMIT/OFFSET 或游标分页,开销明显更高。
- 纯分页需求优先考虑数据库原生分页语法(如 PostgreSQL 的
OFFSET/LIMIT、MySQL 8.0+ 的LIMIT ... OFFSET) -
ROW_NUMBER()更适合做“带名次的筛选”,比如“每个部门薪资前3的员工” - 若必须用它分页,确保
OVER中的ORDER BY列有索引
实际用的时候,最容易被忽略的是 OVER 子句的强制性,以及末尾 ORDER BY 和窗口内 ORDER BY 的分工差异。这两个点没理清,行号要么出不来,要么看起来“乱序”。










