row_number()严格顺序编号不并列、不跳号,rank()值相等则名次并列且后续跳号,dense_rank()并列不跳号;三者核心区别在于对相同排序值的名次处理逻辑。

面试中考察窗口函数,核心是看是否真正理解 RANK() 和 ROW_NUMBER() 的排序逻辑差异——关键不在“怎么写”,而在“为什么结果不同”。
ROW_NUMBER:严格按顺序编号,不跳号、不并列
它只看排序字段的值,对每一行独立分配一个唯一序号,哪怕相邻两行排序字段完全相同,也会强制给出不同编号。
常见用法:
- 取每个分组的“第一条记录”(如最新订单、最早入职员工)
- 实现分页(配合 LIMIT/OFFSET 或直接用 WHERE rn BETWEEN x AND y)
- 去重时保留某一条(如按时间倒序后取 ROW_NUMBER() = 1)
示例:按部门分组,按薪资降序编号
SELECT name, dept, salary,ROW_NUMBER() OVER (PARTITION BY dept ORDER BY salary DESC) AS rn
FROM employees;
若两个员工同属 tech 部且薪资都是 25000,他们会被编为 1 和 2,而非并列第1。
RANK:值相等则名次并列,后续名次跳过
它模拟“体育比赛排名”:相同成绩得相同名次,下一个名次要跳过已占用的位数。比如两个第1名,则下一个是第3名,没有第2名。
适用场景:
- 生成带并列名次的真实排行榜(如销售业绩榜、考试分数榜)
- 筛选“前 N 名”且允许并列时(如 RANK() ≤ 3 可能返回5条记录)
- 和 DENSE_RANK() 对比使用,判断数据分布是否集中
示例:同一张表,改用 RANK
SELECT name, dept, salary,RANK() OVER (PARTITION BY dept ORDER BY salary DESC) AS rk
FROM employees;
如果 tech 部有三人薪资为 25000、25000、24000,则他们的 RANK 是 1、1、3。
三者对比:RANK vs DENSE_RANK vs ROW_NUMBER
面试官常会顺带问 DENSE_RANK(),它是 RANK 的“紧凑版”:并列仍得同名次,但后续名次不跳过。例如:1、1、2 而非 1、1、3。
一句话记住区别:
- ROW_NUMBER:1、2、3、4…(永远连续,无重复)
- RANK:1、1、3、4…(并列→跳号)
- DENSE_RANK:1、1、2、3…(并列→不跳号)
实战避坑提醒
写错往往不是语法问题,而是没想清业务含义:
- 用 ROW_NUMBER 实现“Top 3”可能漏掉并列者;用 RANK 才符合“前三名”的日常理解
- ORDER BY 中遗漏 NULLS FIRST/LAST 处理,可能导致 NULL 值排在最前或最后,影响排名合理性
- PARTITION BY 写错范围(如该按部门却按城市分组),会导致排名逻辑完全偏离需求
- 在子查询中用窗口函数后,忘记给别名或在外部 WHERE 中引用别名(注意:不能直接在同级 WHERE 用窗口函数别名,需嵌套)










