SQL中常用的窗口函数(排序函数)-row_number/r...

对比 SQL 窗口排序函数 row_number、rank、dense_rank、ntile 的返回规则、并列名次差异、适用场景和常见误区,帮助编写稳定的排名类查询。

袋鼠云
袋鼠云

SQL 中常用的窗口函数(排序函数)包括 row_number、rank、dense_rank 和 ntile。它们都需要配合 over 子句使用,可以在不折叠明细行的情况下,为每条记录生成排序编号或分组编号,常用于排名、取 TopN、分桶分析等场景。

基本语法

窗口排序函数的一般写法如下:

SELECT user_id,
       score,
       ROW_NUMBER() OVER (PARTITION BY class_id ORDER BY score DESC) AS rn
FROM exam_score;

partition by 表示按哪个维度分组排名,order by 表示组内排序规则。如果省略分区,函数会在整个结果集上计算。

row_number:连续且不重复

row_number() 会为排序后的每一行生成唯一编号,即使排序字段值相同,也会给出不同序号。例如同分学生仍会得到 1、2、3 这样的连续编号。它最常用于“每组取第一条”“按更新时间保留最新记录”等场景。

为了结果稳定,order by 最好包含唯一或足够确定的字段。例如只按分数排序时,同分记录的先后顺序可能不稳定,可以再追加 id 或创建时间作为次级排序。

rank:并列后跳号

rank() 会给相同排序值相同名次,但后续名次会跳号。例如分数为 100、95、95、90,对应排名可能是 1、2、2、4。它适合体育竞赛、榜单排名等强调并列名次且保留名次间隔的场景。

如果业务要求“并列第二后下一名是第三”,则不应使用 rank,而应考虑 dense_rank。

dense_rank:并列后不跳号

dense_rank() 同样支持并列排名,但后续名次不会跳号。上面的例子会得到 1、2、2、3。它适合统计不同档位、连续等级或需要紧凑排名的分析场景。

在数据报表中,dense_rank 比 rank 更适合展示“第几个不同分值层级”,而 rank 更接近传统竞赛名次。

ntile:平均分桶

ntile(n) 用于把排序后的结果尽量平均分成 n 组,并返回每行所在的桶编号。它常用于用户分层、收入分位、成绩分组等分析。

SELECT user_id,
       amount,
       NTILE(4) OVER (ORDER BY amount DESC) AS quartile
FROM user_amount;

需要注意,ntile 是按行数分桶,不一定保证每个桶的指标总和接近。如果要按金额累计占比分层,需要使用累计窗口函数另行计算。

选择建议

需要唯一序号时用 row_number;需要并列且跳号时用 rank;需要并列但连续排名时用 dense_rank;需要平均分组时用 ntile。实际编写 SQL 时,排序字段的确定性、空值处理和分区口径往往比函数名本身更重要。

开启Data+AI 之旅

填写表单,获取专属解决方案

400-002-1024

工作日 9:00-18:00

关注公众号

获取最新产品动态与技术干货

关注公众号

企业微信

扫码添加企业微信