MySQL 中的窗口函数

ROW_NUMBER()RANK()DENSE_RANK() 这三个都是 SQL 中的窗口函数,用于为结果集中的每一行分配一个排名。它们的核心区别在于如何处理并列(相同排序值) 以及后续排名是否连续


快速对比表

函数 并列处理 排名是否连续 举例(分数: 100,100,90)
ROW_NUMBER() 强行区分,任意给一个顺序(不并列) 1,2,3 ✅ 连续
RANK() 并列占用下一个排名的位置(跳号) 1,1,3 ❌ 不连续
DENSE_RANK() 并列不跳号 1,1,2 ✅ 连续

详细说明与例子

假设有一张成绩表 score

student score
张三 100
李四 100
王五 90
赵六 80

1. ROW_NUMBER()

  • 规则:即使值相同,也强行分出一个唯一序号(通常基于未知或指定的顺序)
  • 结果:1,2,3,4(严格递增,无并列)
SELECT student, score,
       ROW_NUMBER() OVER (ORDER BY score DESC) AS rn
FROM score;
student score rn
张三 100 1
李四 100 2
王五 90 3
赵六 80 4

2. RANK()

  • 规则:并列排名相同,但下一个排名会“跳号”
  • 结果:1,1,3,4
SELECT student, score,
       RANK() OVER (ORDER BY score DESC) AS rk
FROM score;
student score rk
张三 100 1
李四 100 1
王五 90 3
赵六 80 4

3. DENSE_RANK()

  • 规则:并列排名相同,且下一个排名不跳号
  • 结果:1,1,2,3
SELECT student, score,
       DENSE_RANK() OVER (ORDER BY score DESC) AS dr
FROM score;
student score dr
张三 100 1
李四 100 1
王五 90 2
赵六 80 3

典型使用场景

函数 适用场景
ROW_NUMBER() 需要唯一行号,例如分页、去重保留一条、取每组前N条(不关心并列)
RANK() 比赛排名(奥运奖牌榜风格:并列第一后是第三名)
DENSE_RANK() 连续排名需求(例如:“你超过了多少人”的百分比计算)

一个容易被忽略的点

ROW_NUMBER() 不是稳定排序。如果 ORDER BY 列有重复值,ROW_NUMBER() 会随机(或按物理存储顺序)分配序号,但通常不保证一致性。若需确定性顺序,可在 ORDER BY 中加一个唯一列(如 ORDER BY score DESC, id)。


语法结构(通用)

函数名() OVER (
    PARTITION BY 分组列   -- 可选,分组内排名
    ORDER BY 排序列 [ASC|DESC]
)

比如按班级分组排名:

RANK() OVER (PARTITION BY class_id ORDER BY score DESC)

如果你愿意,我也可以给你一个带 PARTITION BY 的实际例子来进一步说明它们三个在分组内的区别。

posted @ 2026-04-14 11:42  LARRY1024  阅读(17)  评论(0)    收藏  举报