ROW_NUMBER、RANK 和 DENSE_RANK 有什么区别?
简化版
ROW_NUMBER 给每行生成唯一序号,即使排序值相同也会继续编号;RANK 遇到并列名次会跳号;DENSE_RANK 遇到并列名次不跳号。比如分数 100、90、90、80,ROW_NUMBER 是 1、2、3、4,RANK 是 1、2、2、4,DENSE_RANK 是 1、2、2、3。
详细版
这三个函数都属于排名窗口函数,常用于 Top N、去重取最新、排行榜、分组排序。它们都需要 OVER (PARTITION BY ... ORDER BY ...) 定义分组和排序。
选择时看业务语义:取每组唯一一条记录用 ROW_NUMBER;排行榜允许并列且名次跳号用 RANK;想要连续名次用 DENSE_RANK。如果排序字段不唯一,ROW_NUMBER 的结果可能不稳定,需要补充唯一排序字段。
面试中最好给具体例子,否则三个函数很容易讲混。
完整版教学
一、共同点
三者都是窗口函数。
都不会像 GROUP BY 那样合并行。
都依赖窗口内排序。
都可以按部门、用户、类目等分区排名。
排名结果通常再被外层查询过滤。
二、基础示例
SELECT
name,
score,
ROW_NUMBER() OVER (ORDER BY score DESC) AS rn,
RANK() OVER (ORDER BY score DESC) AS rnk,
DENSE_RANK() OVER (ORDER BY score DESC) AS dense_rnk
FROM exam_scores;
如果分数相同,RANK 和 DENSE_RANK 会给相同名次。
ROW_NUMBER 仍然会给不同序号。
三、结果对比
| 分数 | ROW_NUMBER | RANK | DENSE_RANK |
|---|---|---|---|
| 100 | 1 | 1 | 1 |
| 90 | 2 | 2 | 2 |
| 90 | 3 | 2 | 2 |
| 80 | 4 | 4 | 3 |
这个表是面试里最清晰的解释方式。
四、典型使用场景
ROW_NUMBER 常用于每组取最新一条。
RANK 常用于真实竞赛排名。
DENSE_RANK 常用于连续档位排名。
如果要求“每个部门薪资前三名,包含并列”,通常用 DENSE_RANK 或 RANK。
如果要求“每个部门只取三行”,通常用 ROW_NUMBER。
五、每组取最新记录
WITH t AS (
SELECT
*,
ROW_NUMBER() OVER (
PARTITION BY user_id
ORDER BY created_at DESC, id DESC
) AS rn
FROM user_events
)
SELECT *
FROM t
WHERE rn = 1;
这里加 id DESC 是为了保证同一时间下排序稳定。
六、并列名次的业务含义
排行榜要提前确认是否允许并列。
并列后是否跳号也要确认。
不同产品对“前三名”的定义不同。
如果第三名并列多人,结果可能超过三行。
排名函数选择不是语法偏好,而是业务规则选择。
七、误区和追问
- 误区:三个函数只是名字不同。 它们对并列排序值的处理完全不同。
- 误区:ROW_NUMBER 排序值相同也稳定。 如果 ORDER BY 不唯一,数据库可以用不同顺序返回并列行。
- 误区:取前三名一定返回三行。 使用
RANK或DENSE_RANK时,并列可能返回超过三行。 - 追问:每组去重保留最新用哪个? 通常用
ROW_NUMBER,并补充唯一排序字段。 - 追问:比赛排名用哪个? 常用
RANK,因为并列后会跳号。 - 追问:薪资前三档用哪个? 常用
DENSE_RANK,因为关注不同薪资档位。
八、面试收束
用一个分数例子解释差异。
再结合去重、排行榜和 Top N 场景说明选择依据。
最后提醒排序稳定性。