SQL 窗口函数 ROW_NUMBER、RANK、DENSE_RANK 常用方法笔记

SQL 窗口函数 ROW_NUMBER、RANK、DENSE_RANK 常用方法笔记

1. ROW_NUMBER()

作用

给查询结果中的每一行生成唯一编号。

特点:

  • 每一行都有唯一序号
  • 不允许出现重复编号
  • 即使排序字段相同,也会继续编号
  • 不存在并列情况

语法

sql 复制代码
ROW_NUMBER() OVER(
    PARTITION BY 分组字段
    ORDER BY 排序字段
)

说明:

text 复制代码
PARTITION BY
        |
        ↓
决定哪些数据属于同一组


ORDER BY
        |
        ↓
决定组内数据排序规则


ROW_NUMBER()
        |
        ↓
按照排序结果生成编号

示例1:不分组编号

原始数据:

姓名 分数
张三 100
李四 90
王五 90
赵六 80

SQL:

sql 复制代码
ROW_NUMBER() OVER(
    ORDER BY SCORE DESC
)

结果:

姓名 分数 ROW_NUMBER
张三 100 1
李四 90 2
王五 90 3
赵六 80 4

理解:

text 复制代码
100分
  |
  ↓
编号1


90分
  |
  ↓
编号2


90分
  |
  ↓
编号3

虽然两个90分相同:

text 复制代码
90
90

但是 ROW_NUMBER 会给每一行不同编号。


常见用途

1. 每组取最新一条数据

例如:

一个保单存在多个版本:

POL_ID UPDATE_TIME
P001 2026-01-01
P001 2026-02-01
P001 2026-03-01

SQL:

sql 复制代码
ROW_NUMBER() OVER(
    PARTITION BY POL_ID
    ORDER BY UPDATE_TIME DESC
) RN

结果:

POL_ID UPDATE_TIME RN
P001 2026-03-01 1
P001 2026-02-01 2
P001 2026-01-01 3

取:

sql 复制代码
WHERE RN = 1

结果:

POL_ID UPDATE_TIME
P001 2026-03-01

业务理解:

text 复制代码
同一个保单
      |
      ↓
按照更新时间倒序
      |
      ↓
最新数据编号=1
      |
      ↓
保留最新记录

2. RANK()

作用

用于排名,相同值排名相同,但是会跳号。

特点:

  • 相同数据排名相同
  • 后面的排名会跳号
  • 适合比赛排名场景

语法

sql 复制代码
RANK() OVER(
    ORDER BY 排序字段 DESC
)

示例

原始数据:

姓名 分数
张三 100
李四 90
王五 90
赵六 80

SQL:

sql 复制代码
RANK() OVER(
    ORDER BY SCORE DESC
)

结果:

姓名 分数 RANK
张三 100 1
李四 90 2
王五 90 2
赵六 80 4

理解:

text 复制代码
第一名

第二名

第二名

第四名

为什么80分是第四名?

因为两个90分:

text 复制代码
第二名
第二名

占用了两个排名位置。

所以:

text 复制代码
1
2
2
4

3. DENSE_RANK()

作用

用于连续排名,相同值排名相同,但是不会跳号。

特点:

  • 相同数据排名相同
  • 后续排名连续
  • 不会产生排名空缺

语法

sql 复制代码
DENSE_RANK() OVER(
    ORDER BY 排序字段 DESC
)

示例

原始数据:

姓名 分数
张三 100
李四 90
王五 90
赵六 80

SQL:

sql 复制代码
DENSE_RANK() OVER(
    ORDER BY SCORE DESC
)

结果:

姓名 分数 DENSE_RANK
张三 100 1
李四 90 2
王五 90 2
赵六 80 3

理解:

text 复制代码
第一名

第二名

第二名

第三名

不会出现:

text 复制代码
1
2
2
4

而是:

text 复制代码
1
2
2
3

4. 三个窗口函数区别

数据:

数据
001
001
002

ROW_NUMBER()

结果:

数据 编号
001 1
001 2
002 3

说明:

不管数据是否重复,每一行都有唯一编号。


RANK()

结果:

数据 编号
001 1
001 1
002 3

说明:

相同数据排名一样,但是后面的编号跳过。


DENSE_RANK()

结果:

数据 编号
001 1
001 1
002 2

说明:

相同数据排名一样,但是后面的编号连续。


5. 三个函数总结对比

函数 是否允许重复 是否跳号 主要用途
ROW_NUMBER 不允许 不跳号 编号、去重、取第一条
RANK 允许 跳号 比赛排名
DENSE_RANK 允许 不跳号 连续排名

6. 快速记忆

ROW_NUMBER()

关键词:

一个数据一个编号

结果:

text 复制代码
1
2
3
4

RANK()

关键词:

比赛排名

结果:

text 复制代码
1
2
2
4

特点:

  • 可以并列
  • 并列占用名次

DENSE_RANK()

关键词:

等级排名

结果:

text 复制代码
1
2
2
3

特点:

  • 可以并列
  • 不浪费编号

7. IFRS17 数据处理中常见场景

ROW_NUMBER() 示例

你的代码:

sql 复制代码
ROW_NUMBER() OVER(
    PARTITION BY 
        a.pol_id,
        a.risk_code,
        a.clm_no,
        (CASE WHEN A.amount >= 0 THEN 0 ELSE 1 END)
    ORDER BY 
        d.SUB_RISK_FLAG
) RN

含义:

按照:

text 复制代码
POL_ID 保单号

+

RISK_CODE 险种代码

+

CLM_NO 理赔号

+

金额正负标识

进行分组。

其中:

sql 复制代码
CASE WHEN A.amount >= 0 THEN 0 ELSE 1 END

表示:

AMOUNT 标识
>=0 0
<0 1

作用:

把:

text 复制代码
正常金额

和:

text 复制代码
冲销金额

分开。

然后:

sql 复制代码
ORDER BY d.SUB_RISK_FLAG

表示:

组内按照主附险标识排序。

最终效果:

text 复制代码
同一个保单
      |
      ↓
同一个险种
      |
      ↓
同一个理赔号
      |
      ↓
同一种金额方向
      |
      ↓
按照主附险排序
      |
      ↓
生成编号

最终记忆

text 复制代码
ROW_NUMBER:

编号
一行一个号码


RANK:

排名
可以并列
但是跳号


DENSE_RANK:

排名
可以并列
但是不跳号

一句话:

ROW_NUMBER 管编号,RANK 管比赛排名,DENSE_RANK 管连续等级排名。

相关推荐
计科土狗1 小时前
GESP六级专题之类与对象
java·前端·数据库
Slow菜鸟2 小时前
第3篇:实操落地篇 · 3套企业标准工作流(IDEA可视化版)
java·ide·intellij-idea
weixin_440784112 小时前
Java基础常见题
java·开发语言·python·java基础
掉鱼的猫2 小时前
Hot-Plug 实战:运行期管理 Solon 插件
java·hotfix
markinmarkin2 小时前
Spring 中有哪些方式可以把Bean 注入到IOC 容器?
java·spring
带刺的坐椅3 小时前
Hot-Plug 实战:运行期管理 Solon 插件
java·solon·插件·热插拔
大黄说说3 小时前
SQL Server 执行计划怎么看?快速定位 SQL 慢的根源
java·linux·数据库
雪之下雪乃的代码日记3 小时前
Python快速入门(Java开发者版)
java·开发语言·笔记·python
敲个大西瓜4 小时前
Springboot核心面试题
java·spring boot·后端