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 小时前
PDF 表格样式优化:jquick-pdf 边框、圆角、背景色
java·开发语言·pdf
景熙55232 小时前
15.Java 8 Stream 流入门到实战
java·开发语言·数据结构
wno7043 小时前
Spring Security权限控制
java·python·spring
杨运交3 小时前
[071][验证码模块]基于Spring拦截器的验证码认证设计思想
java·后端·spring
Geek-Chow4 小时前
CountDownLatch in Java
java
SL_staff4 小时前
从RBAC到场景化授权:《无忧·企业文档》三级权限模型的技术实践解析
java·开源·产品
传奇开心果编程5 小时前
【springboot基础语法学与练】第 1 课:从零开始
java·spring boot·后端·学习
SL_staff5 小时前
财务系统慎用低代码?从数据模型闭环看合规落地的技术实践
java·低代码·全栈
滕州市燕猫虎计算机科技工作室个体工商户5 小时前
IDEA:Command line is too long
java·ide·intellij-idea