ROW_NUMBER()必须配合OVER()使用,否则报错;OVER()中ORDER BY不可省略,PARTITION BY可选但分组编号必需;MySQL 5.7不支持,需8.0+版本。

ROW_NUMBER() 必须配合 OVER() 使用,否则直接报错 Invalid use of aggregate function 或类似语法错误。
ROW_NUMBER() 的基本写法和必要条件
它不是普通函数,而是窗口函数,OVER() 子句不可省略,且至少要指定 ORDER BY。不写 ORDER BY 会触发 SQL 错误(如 PostgreSQL 报 ERROR: window function requires an ordering clause,SQL Server 也拒绝执行)。
-
ROW_NUMBER() OVER (ORDER BY id):按id升序编号,重复值也会得到不同序号 -
ROW_NUMBER() OVER (ORDER BY name DESC):降序排列后编号 - 不能写成
ROW_NUMBER(id)或ROW_NUMBER() ORDER BY id—— 这两种都语法错误
分组内编号:用 PARTITION BY 划分逻辑块
当需要“每个部门内员工按薪资排名”这类需求时,必须加 PARTITION BY department_id。它会在每个分组内独立计数,不跨组延续。
-
ROW_NUMBER() OVER (PARTITION BY dept_id ORDER BY salary DESC):每个dept_id内单独从 1 开始编号 -
PARTITION BY支持多个字段,例如PARTITION BY region, year - 注意:
PARTITION BY的字段必须出现在SELECT或GROUP BY中(取决于是否聚合),否则某些数据库(如 MySQL 8.0+)可能报Unknown column
常见踩坑点:ORDER BY 的字段不在 SELECT 中?
可以。窗口函数的 ORDER BY 是独立作用域,不要求该字段出现在最终 SELECT 列表里。但若用了 PARTITION BY,分区字段最好保留,否则结果难以验证。
- 合法:
SELECT name, ROW_NUMBER() OVER (ORDER BY created_at) AS rn FROM users;——created_at没选出来也没关系 - 危险:
SELECT name FROM users ORDER BY id LIMIT 10;和ROW_NUMBER() OVER (ORDER BY id)行为一致;但如果加了WHERE或JOIN,务必确认OVER()的逻辑与主查询数据集完全对齐 - MySQL 5.7 不支持窗口函数,强行用会报
FUNCTION xxx.ROW_NUMBER does not exist;需确认版本 ≥ 8.0
替代方案:没有 ROW_NUMBER() 怎么办?
旧版 MySQL(
- MySQL 5.7 可用用户变量:
@row := @row + 1 AS rn,但需先SET @row := 0,且在复杂 JOIN 或子查询中易出错、不保证顺序 - SQLite 3.25+ 支持
ROW_NUMBER(),低于此版本只能用(SELECT COUNT(*) FROM t2 WHERE t2.id 类自关联——数据量大时性能极差 - 应用层编号最稳妥:查出结果后用 Python/Java 等语言加索引,避免数据库负担,也规避排序不确定性
真正容易被忽略的是:同一个查询中多次使用 ROW_NUMBER() 时,如果 OVER() 子句不同(比如一个按时间、一个按分数),它们的排序互不影响,但数据库仍需分别执行排序操作——这会显著拖慢大表查询。别以为只是“加个序号”那么简单。

















