4. 窗口函数入门:ROW_NUMBER、RANK、DENSE_RANK 的基本语法与区别
在授信决策引擎中,经常需要对客户按风险评分排序后取前 N 名、计算排名区间或标记批次内偏移位置。传统聚合函数无法保留原始行细节,而窗口函数(Window Function)可以在不改变行数的情况下完成分组排序与编号。本节聚焦三个最常用的排序窗口函数:ROW_NUMBER、RANK 与 DENSE_RANK。
4.1 窗口函数基础语法
所有窗口函数都使用 OVER() 子句定义窗口范围。基本语法结构如下:
<窗口函数>() OVER (
[PARTITION BY <分组列>]
ORDER BY <排序列> [ASC | DESC]
)
| 子句 | 作用 | 授信场景示例 |
|---|---|---|
| PARTITION BY | 按指定列分组,函数在每个分组内独立计算 | 按产品类型分组,分别对客户评分排序 |
| ORDER BY | 指定排序字段与方向,决定编号顺序 | 按风险评分降序排列,评分越高排名越前 |
| ROWS/RANGE | (可选)定义窗口帧边界,排序函数通常省略 | — |
💡 提示: 在授信批次偏移定位中,
PARTITION BY 常用于按“机构”、“产品线”或“渠道”分组,确保排名只在同组内比较,避免跨组干扰。
4.2 三个函数的核心区别
ROW_NUMBER、RANK、DENSE_RANK 都用于生成行号或排名,但处理并列值(tie)的方式截然不同。以下表为例,假设有 6 位客户按信用评分降序排列:
| 客户ID | 信用评分 | ROW_NUMBER | RANK | DENSE_RANK |
|---|---|---|---|---|
| C001 | 95 | 1 | 1 | 1 |
| C002 | 92 | 2 | 2 | 2 |
| C003 | 92 | 3 | 2 | 2 |
| C004 | 88 | 4 | 4 | 3 |
| C005 | 85 | 5 | 5 | 4 |
| C006 | 85 | 6 | 5 | 4 |
- ROW_NUMBER:为每一行分配唯一连续整数,即使评分相同也强制区分(通常按物理顺序或 ORDER BY 中额外字段决定先后)。
- RANK:并列值获得相同排名,但会跳过后续排名号(如并列第 2 名后,下一名是第 4 名)。
- DENSE_RANK:并列值获得相同排名,且不跳过排名号(如并列第 2 名后,下一名是第 3 名)。
📌 授信决策要点: 若需要为每个客户生成唯一偏移序号(如批次内第几笔),使用 ROW_NUMBER;若需要展示“名次”且允许并列空缺(如竞赛排名),使用 RANK;若需要紧凑排名(如分档、评级),使用 DENSE_RANK。
4.3 排名差异可视化
下图直观展示三个函数在并列值出现时的编号行为差异:
4.4 授信场景实战 SQL
以下 SQL 展示在授信申请表中,按产品类型分组,对客户信用评分降序排名:
SELECT
apply_id,
product_type,
credit_score,
ROW_NUMBER() OVER (
PARTITION BY product_type
ORDER BY credit_score DESC, apply_id ASC
) AS row_num,
RANK() OVER (
PARTITION BY product_type
ORDER BY credit_score DESC
) AS rank_val,
DENSE_RANK() OVER (
PARTITION BY product_type
ORDER BY credit_score DESC
) AS dense_rank_val
FROM credit_apply
WHERE apply_date >= '2025-01-01';
⚠️ 常见陷阱: 使用 ROW_NUMBER 时,若 ORDER BY 字段存在重复值且未指定第二排序字段,每次执行可能得到不同的行号顺序,导致批次偏移定位不稳定。建议始终在 ORDER BY 中追加唯一标识列(如 apply_id)作为 tie-breaker。
4.5 选择指南
| 业务需求 | 推荐函数 | 原因 |
|---|---|---|
| 批次内唯一偏移序号(第 1 笔、第 2 笔…) | ROW_NUMBER | 每行唯一编号,无并列 |
| 客户风险排名展示(允许空缺) | RANK | 并列名次后跳过,符合传统排名认知 |
| 客户分档(A/B/C 级,每档连续) | DENSE_RANK | 紧凑编号,不产生空档,便于分箱 |
| 取每组前 N 名(Top-N 查询) | ROW_NUMBER | 精确控制返回行数,避免并列导致多出 |
📌 批次偏移定位应用: 在授信决策引擎中,
ROW_NUMBER 常用于生成“批次内偏移序号”,配合 PARTITION BY batch_id 实现每笔申请在所属批次中的精确位置,为后续偏移量计算和窗口聚合提供基础。