row_number()是窗口函数,必须配合over()使用,且over()中至少需order by;支持mysql 8.0+、postgresql、sql server、oracle及sqlite 3.25+;与rank()、dense_rank()区别在于并列处理方式。

ROW_NUMBER() 必须配合 OVER() 才能用
单独写 ROW_NUMBER() 会报错,不是函数调用失败,而是语法错误——它根本不是独立函数,而是窗口函数,必须绑定 OVER() 子句。很多人卡在这一步,以为漏装扩展或版本太低,其实只是少写了括号里的东西。
常见错误现象:ERROR: window function ROW_NUMBER requires an OVER clause
-
OVER()里至少得有ORDER BY,否则语法不合法(即使你只想编号不关心顺序) - 如果还要分组内排序,
PARTITION BY放在ORDER BY前面,顺序不能反 - MySQL 8.0+、PostgreSQL、SQL Server、Oracle 都支持;SQLite 3.25+ 也行,但旧版不行
示例:按部门分组,给每个员工按薪资降序编号
SELECT name, dept, salary,
ROW_NUMBER() OVER (PARTITION BY dept ORDER BY salary DESC) AS rn
FROM employees;
分组内排序 vs 全局排序,就看有没有 PARTITION BY
PARTITION BY 是分组的开关,不是可选项。漏掉它,ROW_NUMBER() 就变成对整张表排序编号,和你想要的“每个部门内部排”完全不是一回事。
使用场景差异:
- 要「每个班级里按分数排前3名」→ 必须
PARTITION BY class - 要「全校总分排名」→ 只写
ORDER BY score DESC,不加PARTITION BY - 想按时间先后编号但忽略分组 →
OVER (ORDER BY created_at),连PARTITION BY都不用
性能影响:加了 PARTITION BY 后,数据库需要先做分组哈希或排序,比纯全局排序略慢,但通常可接受;如果分区字段没索引,大表上可能明显变慢。
ROW_NUMBER() 和 RANK()、DENSE_RANK() 的区别在哪
三者都编号,但处理并列的方式不同——这直接决定你该选谁。别只图 ROW_NUMBER() 名字顺口,用错会导致业务逻辑出错。
假设两人同分并列第1:
-
ROW_NUMBER():1, 2, 3…(强行不重复,哪怕值一样) -
RANK():1, 1, 3…(并列占位,跳过下一名次) -
DENSE_RANK():1, 1, 2…(并列不占位,连续往下排)
典型误用:用 ROW_NUMBER() 实现「取每组最高分」时,写成 WHERE rn = 1 是对的;但若想取「所有并列第一」,就必须换 RANK() 或 DENSE_RANK(),否则漏数据。
ORDER BY 里多个字段会影响编号稳定性
ORDER BY 不只是决定谁排前面,还决定了编号是否可复现。如果排序字段有重复值,又没加二级排序,数据库可能每次返回不同编号顺序——尤其在分布式或并行执行环境下。
- 比如只写
ORDER BY salary,多个员工同薪,ROW_NUMBER()分配的序号可能随机波动 - 解决办法:加一个唯一字段兜底,如
ORDER BY salary DESC, emp_id - MySQL 8.0 默认启用
sql_mode=ONLY_FULL_GROUP_BY,对OVER()里的ORDER BY没强制要求唯一性,但生产环境强烈建议补全
这个细节不报错,也不警告,但上线后查数据对不上,排查起来特别费时间。










