row_number() 是窗口函数,必须配合 over() 使用,且 over 中必须含 order by;不支持分组时全表编号,支持 partition by 实现分组内编号;不可与 group by 混用;mysql 5.7 及更早版本不支持。

ROW_NUMBER() 必须配合 OVER() 使用,否则直接报错
单独写 ROW_NUMBER() 会触发语法错误,比如 MySQL 8.0+ 或 PostgreSQL 报 function row_number() requires a window specification,SQL Server 报 Incorrect syntax near ')' 。它不是普通函数,而是窗口函数,必须搭配 OVER() 子句定义排序和分区逻辑。
最简可用形式是:ROW_NUMBER() OVER (ORDER BY some_column)。不加 PARTITION BY 就是全表连续编号;加了才按分组重置计数。
分组内编号要写对 PARTITION BY,别和 GROUP BY 混用
PARTITION BY 是窗口函数的分组,GROUP BY 是聚合语句的分组,二者不能互相替代。如果在 SELECT 中用了 ROW_NUMBER(),又同时写了 GROUP BY,大概率报错或结果异常——因为窗口函数在 GROUP BY 之后执行,但行数已聚合压缩。
- 正确做法:只用
OVER (PARTITION BY category ORDER BY created_at)实现“每个 category 内按时间排序编号” - 错误写法:
SELECT category, ROW_NUMBER() OVER (...) FROM t GROUP BY category—— 这会导致每组只剩一行,ROW_NUMBER()失去意义 - 注意:MySQL 5.7 不支持窗口函数,必须升级到 8.0+;SQLite 3.25+ 才支持
ORDER BY 在 OVER() 里不可省略,否则编号顺序不确定
ROW_NUMBER() 要求明确排序依据,OVER () 里没写 ORDER BY 会报错(如 PostgreSQL 报 window function row_number requires an ordering clause)。即使业务上觉得“顺序无所谓”,也得显式写个确定性字段,比如主键:ORDER BY id。
常见陷阱:
- 用
ORDER BY RAND()能跑,但每次执行结果不同,不适合分页或幂等场景 - 多个字段排序时,若存在重复值(如多行
status = 'done'),需补一个唯一字段(如id)避免编号不稳定 - NULL 值默认排在最前(PostgreSQL/SQL Server)或最后(MySQL),影响位置计算,必要时用
ORDER BY col ASC NULLS LAST(PostgreSQL 支持,MySQL 不支持该语法)
ROW_NUMBER() 和 RANK()、DENSE_RANK() 的编号逻辑差异很关键
三者都生成序号,但处理并列的方式完全不同,选错会导致业务逻辑出错。比如同一分组中两行并列第一:
-
ROW_NUMBER():强制给不同序号 → 1, 2, 3(哪怕值相同) -
RANK():并列则跳号 → 1, 1, 3 -
DENSE_RANK():并列不跳号 → 1, 1, 2
典型误用:想取“每个部门工资最高的员工”,用 ROW_NUMBER() OVER (PARTITION BY dept ORDER BY salary DESC) 没问题;但如果最高工资有多人,RANK() 才能确保他们都拿到 1 —— ROW_NUMBER() 只会挑出其中一个。
实际写法示例(取各部门 top 3 高薪):
SELECT dept, name, salary, rn<br>FROM (<br> SELECT dept, name, salary,<br> ROW_NUMBER() OVER (PARTITION BY dept ORDER BY salary DESC, id) AS rn<br> FROM employees<br>) t<br>WHERE rn <p>这里补了 <code>id</code> 是为了在 salary 相同时保证排序稳定,避免同一批数据多次执行结果不一致。</p>










