SQL窗口函数中的ROW_NUMBER、RANK、DENSE_RANK和NTILE都属于排序类窗口函数,但在业务含义上有明显区别。理解它们各自适合的场景,可以帮助我们在写分析SQL时快速选型,而不必每次都临时推导逻辑。

一、ROW_NUMBER:分组内唯一序号,适合去重与取第一条
ROW_NUMBER在不考虑并列的情况下,为每一行分配一个连续且不重复的数字。典型业务场景是取每个用户最近一笔订单,或剔除完全重复的记录。
-- 取每个用户最近的一笔订单
SELECT user_id, order_id, create_time
FROM (
SELECT
user_id,
order_id,
create_time,
ROW_NUMBER() OVER (PARTITION BY user_id ORDER BY create_time DESC) AS rn
FROM orders
) t
WHERE rn = 1;
二、RANK与DENSE_RANK:排名场景下的并列处理
RANK会在出现并列时跳过后续名次,而DENSE_RANK不会跳过。例如成绩排名中,两个并列第一后,RANK的下一名是第三,DENSE_RANK的下一名是第二。
| 分数 | RANK | DENSE_RANK |
|---|---|---|
| 100 | 1 | 1 |
| 100 | 1 | 1 |
| 90 | 3 | 2 |
-- 查询学生成绩排名,展示两种排名差异 SELECT student_name, score, RANK() OVER (ORDER BY score DESC) AS rk, DENSE_RANK() OVER (ORDER BY score DESC) AS drk FROM exam_score;
业务模板建议
- 需要名次间断(如竞赛颁奖):使用RANK
- 需要连续等级(如会员分级):使用DENSE_RANK
三、NTILE:等频分桶,适合用户分层
NTILE可以把有序数据切成N个桶,每个桶行数尽量相等。常用于将用户按消费额分为高、中、低三组,或做四分位分析。
-- 将用户按消费金额分为4组 SELECT user_id, total_amount, NTILE(4) OVER (ORDER BY total_amount DESC) AS level_bucket FROM user_consumption;
四、综合对比与选型
当需求是“每组取前N条且不允许并列占多行”时,优先ROW_NUMBER;当需求是“展示排名且并列合理”时,根据是否跳号选择RANK或DENSE_RANK;当需求是“把数据均匀分段”时,使用NTILE。把这些模板存入常用SQL片段,业务开发效率会明显提升。
注意:窗口函数不会减少原表行数,只是新增计算列,过滤需在子查询或外层WHERE中完成。
SQL窗口函数ROW_NUMBERRANK修改时间:2026-07-26 16:57:17