RANK()并列排名会跳号,ROW_NUMBER()严格连续编号;两者须同用OVER(ORDER BY ...)对比,且最外层需另加ORDER BY控制输出顺序。
怎么让 RANK() 和 ROW_NUMBER() 的结果一眼看出区别
直接看排序值是否“跳号”——rank() 遇到相同值会并列且跳过后续序号,row_number() 则严格按行物理顺序编号,绝不重复也不跳。
常见错误是只查一列排序字段,没加 ORDER BY 或忘了用 PARTITION BY 分组,导致结果看似随机。窗口函数不指定 ORDER BY 就没有确定性排序,数据库可能返回任意顺序。
-
RANK()适合排名场景:比如“成绩并列第2,下一个是第4”,需关注业务是否接受跳号 -
ROW_NUMBER()适合分页、取 Top N、去重(配合PARTITION BY)等需要唯一序号的场景 - 两者都必须写在
SELECT子句里,不能出现在WHERE或GROUP BY中(会报错window function is not allowed here)
SQL 示例里怎么写才能同时对比两个函数
关键是在同一个查询中并列调用,共用相同的 OVER 子句,否则比较失去意义。注意括号和逗号位置——OVER (ORDER BY score DESC) 必须完整包裹,漏括号会报错 missing )。
SELECT name, score, RANK() OVER (ORDER BY score DESC) AS rnk, ROW_NUMBER() OVER (ORDER BY score DESC) AS rn FROM students;
如果数据里有两条 score=95,rnk 会显示两个 1,然后下一个非 95 的记录 rnk 是 3;而 rn 一定显示 1 和 2,再下一个是 3。
为什么加了 PARTITION BY 后结果还是不对
分区后每个组内独立计算序号,但很多人忽略“组内排序仍需 ORDER BY”。只写 PARTITION BY dept 不写 ORDER BY,每组内的序号仍是未定义的,MySQL 可能按插入顺序,PostgreSQL 可能按磁盘顺序,结果不可复现。
- 正确写法:
ROW_NUMBER() OVER (PARTITION BY dept ORDER BY salary DESC) - 错误写法:
ROW_NUMBER() OVER (PARTITION BY dept)—— 会警告或报错,取决于数据库版本 - 性能影响:分区字段和排序字段最好都有索引,否则大表上窗口函数会全表扫描+内存排序
ORDER BY 在窗口函数和外部查询里冲突怎么办
窗口函数里的 ORDER BY 只管排序逻辑,不影响最终结果集顺序;最终显示顺序由最外层 ORDER BY 决定。两者不冲突,但容易误以为“写了就生效”。
典型踩坑:查出 RANK() 后发现序号对,但数据显示乱序——因为没加最外层 ORDER BY name 或 ORDER BY rnk。
- 窗口
ORDER BY:决定谁排第几(计算依赖) - 查询末尾
ORDER BY:决定屏幕/结果集怎么展示(输出控制) - 如果省略最外层
ORDER BY,SQL 标准不保证返回顺序,哪怕看起来有序,换一次执行就可能变
ORDER BY 不等于查询的 ORDER BY,少写一个,结果就不是你“以为”的那个样子。










