当前位置:首页 > 问答 > 正文

SQL Server里那些排名函数到底怎么用,弄懂它们其实没那么难

很多刚开始用SQL Server的朋友,一看到ROW_NUMBERRANKDENSE_RANKNTILE这些排名函数就有点头大,感觉它们长得差不多,用起来又怕搞混,只要理解了它们核心的区别,用起来非常简单,今天我们就用大白话把它们讲清楚。

想象一个场景:你们班进行了一次考试,现在有一张成绩表,里面有学生姓名和分数,老师想看看大家的排名情况,这时候排名函数就派上用场了。

我们来认识第一个,也是最常用的:ROW_NUMBER()

这个名字直译过来就是“行号”,它的作用最简单:就是不管三七二十一,按照你指定的顺序,给每一行一个唯一的、连续的号码,从1开始。

我们按分数从高到低排名: SELECT 学生姓名, 分数, ROW_NUMBER() OVER (ORDER BY 分数 DESC) AS 排名 FROM 成绩表

结果可能是: 小明 100分 排名1 小红 98分 排名2 小刚 98分 排名3 小丽 95分 排名4

你看,即使小红和小刚都是98分,并列第二,但ROW_NUMBER()很“死板”,它必须给出不一样的号码,所以硬是给了小刚一个第3名,它只关心行的顺序,不关心值是否相同。

那如果我想让分数一样的同学并列排名呢?这时候就要用RANK()了

RANK函数就智能多了,它会考虑值是否相同,如果值相同,就给它们相同的排名。

还用同样的数据和排序: SELECT 学生姓名, 分数, RANK() OVER (ORDER BY 分数 DESC) AS 排名 FROM 成绩表

结果会变成: 小明 100分 排名1 小红 98分 排名2 小刚 98分 排名2 -- 注意,这里和小红并列第2了 小丽 95分 排名4 -- 注意!排名直接跳到了第4

RANK的规则是:并列的排名会占用名次,小红和小刚并列第二,他们俩就把第二名这个位置给“占”了,下一个分数不同的人(小丽)就只能排到第4名(因为第3名已经被“跳过”了)。

我们觉得跳过名次不太直观,希望排名是连续的,这时候DENSE_RANK()就登场了

DENSE_RANK翻译过来是“密集排名”,它也会让相同的值并列,但不会跳过名次。

同样的情况: SELECT 学生姓名, 分数, DENSE_RANK() OVER (ORDER BY 分数 DESC) AS 排名 FROM 成绩表

结果: 小明 100分 排名1 小红 98分 排名2 小刚 98分 排名2 -- 依然并列第2 小丽 95分 排名3 -- 看这里!排名是连续的3,没有跳过

DENSE_RANK的好处是排名数字是连续的,更符合我们一些日常数数的习惯。

简单总结一下这三个核心函数的区别:

  • ROW_NUMBER():连续唯一,不并列,像报数1,2,3,4...
  • RANK():并列,但会跳过后续名次,像比赛颁奖,有并列冠军,就没有亚军,下一个是季军。
  • DENSE_RANK():并列,且不跳名次,排名数字连续,像“第一梯队”、“第二梯队”这种分组。

别忘了重要的PARTITION BY

上面我们都是在整个班级(整张表)里排名,但OVER子句里还有一个超级有用的东西叫PARTITION BY,意思是“按...分组”,你可以把它理解成“先分组,再在组内排名”。

成绩表里还有班级列,我们想看看每个班级内部的排名: SELECT 班级, 学生姓名, 分数, ROW_NUMBER() OVER (PARTITION BY 班级 ORDER BY 分数 DESC) AS 班级内排名 FROM 成绩表

这个查询会先按班级把学生分开(比如一班和二班),然后在一班内部按分数从高到低排1,2,3...,在二班内部再重新从1开始排1,2,3...。PARTITION BYORDER BY组合在一起,构成了排名函数完整的逻辑。

我们看一眼NTILE()

这个函数有点特别,它不完全是排名,更像是“分桶”或“分组”,你需要告诉它你想分成多少份(N份)。

老师想根据成绩把全班同学分成4个梯队(比如前25%是第一梯队,接着25%是第二梯队...): SELECT 学生姓名, 分数, NTILE(4) OVER (ORDER BY 分数 DESC) AS 梯队 FROM 成绩表

NTILE(4)会尽量平均地把所有学生分成4组,并给每个学生标上他属于第几组(1到4),如果总人数不能被4整除,那么多出来的人会依次放在前面的组里。

实际应用小提示

这些排名函数特别有用,经常用来解决一些棘手的问题,

  1. 删除重复数据:用ROW_NUMBER() PARTITION BY重复的字段,然后删除排名大于1的记录,可以保留唯一数据。
  2. 查询每个分组的前N名:比如查询每个部门工资最高的3个人,用ROW_NUMBER() PARTITION BY 部门,然后外面套一个查询,筛选排名<=3就行。
  3. 数据分页ROW_NUMBER()是实现分页查询的经典方法。

SQL Server这几个排名函数的核心就是OVER子句里的ORDER BY(决定顺序)和PARTITION BY(决定分组),只要抓住ROW_NUMBER(不并列)、RANK(并列跳号)、DENSE_RANK(并列连续)这三个的本质区别,再多加练习,你就能轻松驾驭它们了。

SQL Server里那些排名函数到底怎么用,弄懂它们其实没那么难