SQL 开窗函数排序详解

SQL 开窗函数排序详解

ROW_NUMBER vs RANK vs DENSE_RANK vs NTILE vs PERCENT_RANK

五大排序开窗函数对比

函数 相同值处理 排名连续性 特点 典型场景
ROW_NUMBER() 随机/按顺序分配唯一序号 连续 无重复序号 分页、去重、分配唯一ID
RANK() 相同值同排名,占多个位置 跳跃 1,1,3,4(跳2) 竞赛排名、允许并列
DENSE_RANK() 相同值同排名,不占位置 连续 1,1,2,3(不跳) 等级划分、连续评级
NTILE(n) 强制分n组 连续 等分桶 分位数、AB测试分组
PERCENT_RANK() 计算百分比排名 0-1之间 (rank-1)/(总行数-1) 百分位分析

直观对比示例

假设成绩表 scores:

复制代码
SELECT 
    学生,
    分数,
    ROW_NUMBER() OVER (ORDER BY 分数 DESC) AS rn,
    RANK() OVER (ORDER BY 分数 DESC) AS rk,
    DENSE_RANK() OVER (ORDER BY 分数 DESC) AS drk,
    NTILE(3) OVER (ORDER BY 分数 DESC) AS nt,
    ROUND(PERCENT_RANK() OVER (ORDER BY 分数 DESC), 2) AS pr
FROM scores;

执行结果对比

学生 分数 ROW_NUMBER RANK DENSE_RANK NTILE(3) PERCENT_RANK
张三 100 1 1 1 1 0.00
李四 100 2 1 1 1 0.00
王五 90 3 3 2 2 0.40
赵六 80 4 4 3 2 0.60
孙七 80 5 4 3 3 0.60
周八 70 6 6 4 3 1.00

💡

关键观察:

• 张三和李四分数相同(100分),RANK() 和 DENSE_RANK() 都给他们并列第1

• 王五90分,RANK() 给他第3名(跳过了第2),而 DENSE_RANK() 给他第2名(连续)

• ROW_NUMBER() 强制给李四第2名(即使分数相同)

各函数详解与示例

  1. ROW_NUMBER()

为每一行分配唯一的连续序号,即使值相同也强制排序。

**用途:**分页查询、去重保留一条、分配唯一ID

  1. RANK()

相同值同排名,下一名跳过中间名次(跳号)。

**用途:**竞赛排名、奥运奖牌榜、考试排名

  1. DENSE_RANK()

相同值同排名,下一名紧接(不跳号)。

**用途:**等级评定(A/B/C/D)、连续评级

  1. NTILE(n)

强制将数据分成n组,每组人数尽可能相等。

**用途:**前25%用户、AB测试分组、分位数分析

代码示例

复制代码
-- 1. ROW_NUMBER():每班前3名,分数相同只取一个
SELECT * FROM (
    SELECT *, ROW_NUMBER() OVER (PARTITION BY 班级 ORDER BY 成绩 DESC) AS rn
    FROM students
) WHERE rn <= 3;

-- 2. NTILE():按消费金额分4组(ABCD等级)
SELECT 
    NTILE(4) OVER (ORDER BY 消费金额 DESC) AS 消费等级,
    NTILE(10) OVER (ORDER BY 活跃度 DESC) AS 活跃十分位
FROM users;

-- 3. PERCENT_RANK():计算百分位
SELECT 
    学生,
    ROUND(PERCENT_RANK() OVER (ORDER BY 分数), 2) AS 百分位
FROM scores;
-- 结果:0=第1名,1=最后1名,0.9=超过90%的人

使用场景速查表

  • 每班前3名,分数相同只取一个ROW_NUMBER()
  • 竞赛排名,允许并列,跳号RANK()
  • 等级划分(优秀/良好/及格)DENSE_RANK()
  • 按成绩分4组(ABCD等级)NTILE(4)
  • 计算成绩超过90%的同学PERCENT_RANK()
  • 分页查询(第2页,每页10条)ROW_NUMBER()
  • 找出销售额前20%的店铺NTILE(5)

窗口函数完整语法

复制代码
函数名() OVER (
    [PARTITION BY 分组列]     -- 分组(可选)
    [ORDER BY 排序列]          -- 排序(可选)
    [ROWS/RANGE 窗口范围]      -- 滑动窗口(可选)
)

分组排名示例

复制代码
SELECT 
    班级,
    学生,
    分数,
    RANK() OVER (PARTITION BY 班级 ORDER BY 分数 DESC) AS 班内排名
FROM scores;
-- 结果:每个班级内部独立排名

数据库支持情况

MySQL 8.0+PostgreSQLSQL ServerOracleSQLite 3.25+Spark SQLHiveClickHouse

相关推荐
摇滚侠5 小时前
《On Java 中文版 基础卷》阅读笔记 实现隐藏 12
java·数据库·笔记
川石课堂软件测试5 小时前
学习软件测试需掌握的一些知识
数据库·python·sql·功能测试·网络协议·mysql·http
2501_937767166 小时前
自建 SQL 数据库定时备份踩坑复盘与落地思路
数据库·sql
silvamux_7 小时前
10款模型写种草笔记:可发布性、返工来源与成本数据缺口复盘
java·数据库·笔记
I Am a robert girl9 小时前
从 GameHorizon 拆解多时间尺度游戏评测:数据管线、离线基准与在线回放的三层设计
数据库·游戏·多时间尺度·数据管线·游戏评测·离线基准·在线回放
躺柒9 小时前
读数据安全架构设计与实践17安全架构案例(下)
数据库·安全·零信任·安全架构·防火墙·无边界
SelectDB9 小时前
实时更新排错现场:导入了却查到旧数据,和 FINAL 越加越慢的两条路
大数据·数据库·数据分析
SelectDB10 小时前
拿 Planet 的账单一行行对下来,我总结出三个可自查的校验点
大数据·数据库·数据分析
SelectDB10 小时前
Apache Doris + Vane:让多模态数据进入业务分析
大数据·数据库·数据分析
pjj1985412 小时前
ClickHouse 与 Doris 数据库技术梳理:看懂分析型数据库
数据库·clickhouse