row_number() 必须配合 over() 使用,否则报错;它是窗口函数,需指定 order by 排序,可选 partition by 分组编号,且不能在 where 中直接引用别名。

ROW_NUMBER() 必须配合 OVER() 使用,否则报错
直接写 SELECT ROW_NUMBER() 会触发错误:「窗口函数必须有 OVER 子句」。它不是普通标量函数,而是窗口函数,依赖排序和分组逻辑才能产出序号。
常见错误写法:SELECT name, ROW_NUMBER() —— 缺少 OVER,SQL 引擎无法知道“按什么排序”“是否要分组”。
正确结构是:ROW_NUMBER() OVER (ORDER BY ...) 或带 PARTITION BY 的完整形式。
PARTITION BY 控制“每个类别内独立编号”
想按类别(比如 category)分别编号,就得用 PARTITION BY category。它把数据按该列值切分成多个逻辑分区,每个分区内部从 1 开始重新计数。
示例语句:
SELECT id, product_name, category, ROW_NUMBER() OVER (PARTITION BY category ORDER BY price DESC) AS rn FROM products;
注意点:
-
PARTITION BY后不能跟表达式或函数(如PARTITION BY UPPER(category)在部分数据库中不支持) - 如果漏掉
ORDER BY,多数数据库(如 PostgreSQL、SQL Server)会拒绝执行;MySQL 8.0+ 允许但结果不可预测 -
ORDER BY决定同一类别内编号顺序,相同值时序号仍递增(无稳定排序则可能每次运行结果不同)
ORDER BY 中的字段必须可比较且尽量唯一
当 ORDER BY 字段存在重复值(例如多个商品价格都是 99),ROW_NUMBER() 仍会强制分配不同序号,但顺序不稳定 —— 下次查询可能交换位置。
为避免歧义,建议补一个唯一字段兜底:
ROW_NUMBER() OVER ( PARTITION BY category ORDER BY price DESC, id ASC ) AS rn
这样即使价格相同,也会按 id 排序,保证结果确定性。
其他影响:
- 排序字段越多,开销越大,尤其大数据量时注意索引覆盖(如建联合索引
(category, price, id)) - 某些数据库(如旧版 MySQL)不支持在窗口函数
ORDER BY中使用别名,必须写原始列名
别名不能在 WHERE 或 GROUP BY 中直接引用
ROW_NUMBER() 是窗口计算,在 SQL 执行顺序中晚于 WHERE 和 GROUP BY,所以不能写 WHERE rn = 1 —— 会报错「列不存在」。
正确做法是套一层子查询或 CTE:
WITH ranked AS (
SELECT *,
ROW_NUMBER() OVER (PARTITION BY category ORDER BY price DESC) AS rn
FROM products
)
SELECT * FROM ranked WHERE rn = 1;
容易忽略的细节:
- CTE 或子查询里不能同时用
SELECT *和窗口函数别名做筛选,必须显式列出所有需要字段 - 若需取每类最贵商品,
rn = 1可行;但若要排除并列第一的情况,得改用RANK()或DENSE_RANK() - 有些 ORM(如 Django ORM)不原生支持窗口函数,需用 raw SQL 或数据库视图绕过
实际用的时候,最常卡在 PARTITION BY 写错位置、ORDER BY 缺失、或者试图在 WHERE 里直接用 rn —— 这三个地方多检查一遍,基本就能跑通。











