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 管连续等级排名。

相关推荐
码农小河6614 小时前
基于SSM+JSP的高校专业信息管理系统【附源码+数据库】
java·开发语言·数据库
风若飞16 小时前
Spring Ai 入门遇到问题1
java·后端·spring
Nuanyt17 小时前
LeetCode Hot 100 链表专题(五)· 2 题(Java)
java·算法·leetcode·链表
黑马程序员毕设17 小时前
基于 Java 的餐饮点餐系统设计与应用报告
java·开发语言
SL_staff17 小时前
从文档工具到知识中枢:基于JVS数字底座构建企业级统一内容管理平台的技术实践
java·开源·全栈
SL_staff17 小时前
从‘连得上’到‘管得好’:JVS-IOT双引擎驱动设备运维闭环
java·物联网·产品
w_zero_one20 小时前
递归算法(一)
java·开发语言·算法
SL_staff20 小时前
私有化低代码不是减配版开发:JVS双模式建模如何重建IT交付信任
java·低代码·spring cloud
墨着染霜华20 小时前
Redocly 生成 OpenAPI 接口文档踩坑实录|Node 版本兼容 + 接口地址错误问题解决
java
文丑颜不良啊21 小时前
LeetCode1881~1990题目解析
java·leetcode