排序中常见的三种窗口函数:ROW_NUMBER(),RANK(),DENSE_RANK()
ROW_NUMBER() :连续排名
DENSE_RANK() :并列连续排名
RANK() :并列跳跃排名
复制
mysql 8.0支持窗口函数了,氮素目前常用的版本中,还是不支持窗口函数的,所以接下来会介绍一下用变量来实现各种排序的方法。
为了方便大家理解,可以先看一下接下来代码中会用到表结构:
CREATE TABLE `scores` (
`id` int(11) NOT NULL COMMENT 'ID',
`name` varchar(255) DEFAULT NULL COMMENT '姓名',
`course_id` varchar(255) DEFAULT NULL COMMENT '课程ID',
`score` int(11) DEFAULT NULL COMMENT '成绩',
PRIMARY KEY (`id`)
) ;
复制
以此表为基础,将通过处理两个问题来展示这三种排序方式各自的特点:
对成绩进行排名
根据课程分组后对成绩进行排名
一.连续排名
相同的值,依旧按照连续数字进行排名
1--ROW_NUMBER()实现 窗口函数,mysql8.0以下版本不支持,了解一下就行
2SELECT score,
3ROW_NUMBER() OVER (ORDER BY score DESC) ranking
4FROM SCORES;复制
1--使用变量实现
2-- :=是mysql中的赋值
3--这里的cur_rank是先+1然后再赋值给自己
4SELECT score,
5 (@cur_rank := @cur_rank + 1) ranking
6FROM SCORES s,
7(SELECT @cur_rank := 0) r
8ORDER BY score DESC;复制
1--ROW_NUMBER()结合PARTITION BY
2SELECT t.course_id,
3 t.score,
4 ROW_NUMBER() OVER(PARTITION BY t.course_id order by t.score DESC) as ranking
5FROM SCORES t;复制
1-- 变量和IF实现
2-- 新增的@pre_rank用来记录courseid,通过IF语句判断每一行课程id和上一行是否相等
3SELECT t.course_id,
4 t.score,
5 @cur_rank :=IF(@pre_rank=course_id,@cur_rank+1,1) as ranking,
6 @pre_rank :=course_id
7FROM SCORES t,
8(SELECT @cur_rank := 0,@pre_rank=null) r
9order by course_id ASC,score DESC;
10
11-- 变量和CASE WHEN实现
12SELECT t.course_id,
13 t.score,
14 case when @pre_rank=course_id then @cur_rank:=@cur_rank+1
15 when @pre_rank :=course_id then @cur_rank:=1
16 end as ranging
17FROM SCORES t,
18(SELECT @cur_rank := 0,@pre_rank=null) r
19order by course_id ASC,score DESC;复制
IF语句 和 CASE WHEN语句 的效果是一样的,可以根据日常使用习惯自行选择,但在使用CASE WHEN语句 时要注意,不能直接用 CASE WHEN ... ELSE 。需要用when语句把变量的赋值写清楚。
二.并列连续排名
并列即相同的值,相同的值保留重复名次,遇到下一个不同值时,依然按照连续数字排名
1--DENSE_RANK()实现 窗口函数,mysql 8.0以下版本不支持
2SELECT num,
3 DENSE_RANK() OVER(ORDER BY rank DESC)
4FROM SCORES;复制
1--变量和IF实现
2--这里的 @pre_rank变量用来记录成绩,然后通过IF语句判断和上一行的成绩是否相等
3SELECT score,
4IF(@pre_rank = score, @cur_rank, @cur_rank := @cur_rank + 1) ranking,
5@pre_rank := score
6FROM SCORES s, (SELECT @cur_rank :=0, @pre_rank = NULL) r
7ORDER BY score DESC;
8
9--变量和case when
10SELECT score,
11 case when @pre_rank = score then @cur_rank -- 即@cur_rank:= @cur_rank
12 when @pre_rank := score then @cur_rank := @cur_rank + 1
13 as ranking
14FROM SCORES s, (SELECT @cur_rank :=0, @pre_rank = NULL) r
15ORDER BY score DESC;复制
1--DENSE_RANK() 结合PARTITION BY
2SELECT course_id,
3 score,
4 DENSE_RANK() OVER(PARTITION BY course_id ORDER BY score DESC)
5FROM scores;复制
1-- 变量和IF语句
2-- @pre_rank 记录成绩, @pre_course_id 记录科目
3-- 可以看出, 用来记录源数据的变量初始值一般是null
4SELECT course_id,
5 score,
6 IF(@pre_rank = score, @cur_rank, @cur_rank := @cur_rank + 1),
7 @pre_rank := score,
8 IF(@pre_course_id = course_id, @cur_rank, @cur_rank := 1) ranking,
9 @pre_course_id := course_id
10FROM SCORES s,
11(SELECT @cur_rank := 0, @pre_rank = NULL,@pre_course_id := NULL) r
12ORDER BY course_id ASC,score DESC;复制
三.并列跳跃排名
并列即相同的值,相同的值保留重复名次,遇到下一个不同值时,跳跃到总共的排名
1--RANK() 函数 窗口函数,mysql 8.0以下版本不支持
2SELECT *,
3 RANK() OVER(ORDER BY score DESC)
4FROM SCORES;复制
1-- 变量和 if 实现
2-- 新增的@rank_counter用来记录原始排名
3SELECT score,
4 @rank_counter := @rank_counter + 1,
5 IF(@pre_rank = score, @cur_rank, @cur_rank := @rank_counter) ranking,
6 @pre_rank := score
7FROM SCORES s,
8(SELECT @cur_rank :=0, @pre_rank := NULL, @rank_counter := 0) r
9ORDER BY score DESC;
10
11-- 变量和CASE WHEN 实现
12SELECT score,
13 @rank_counter := @rank_counter + 1,
14 case when @pre_rank = score then @cur_rank --即@cur_rank :=@cur_rank
15 when @pre_rank := score then @cur_rank := @rank_counter
16 end as ranking
17FROM SCORES s, (SELECT @cur_rank :=0, @pre_rank := NULL, @rank_counter := 0) r
18ORDER BY score DESC;复制
1--RANK()结合PARTITION BY
2SELECT course_id,
3 score,
4 RANK() OVER(PARTITION BY course_id ORDER BY score DESC)
5FROM SCORES;复制
1-- 变量和IF语句
2SELECT course_id,
3 score,
4 @rank_counter := IF(@pre_course_id = s.course_id,@rank_counter + 1,1),
5 IF(@pre_course_id = s.course_id,IF(@pre_rank = s.score, @cur_rank, @cur_rank := @rank_counter),@cur_rank := 1) ranking,
6 @pre_rank := s.score,
7 @pre_course_id := s.course_id
8FROM SCORES s,
9(SELECT @cur_rank :=0, @pre_rank := NULL, @rank_counter := 0,@cur_couse:=null) r
10ORDER BY course_id ASC,score DESC;复制
文章转载自李二白,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。
评论
相关阅读
【MySQL 30周年庆】MySQL 8.0 OCP考试限时免费!教你免费领考券
墨天轮小教习
484次阅读
2025-04-25 18:53:11
墨天轮个人数说知识点合集
JiekeXu
445次阅读
2025-04-01 15:56:03
MySQL数据库当前和历史事务分析
听见风的声音
426次阅读
2025-04-01 08:47:17
MySQL 30 周年庆!MySQL 8.4 认证免费考!这次是认真的。。。
严少安
409次阅读
2025-04-25 15:30:58
MySQL 生产实践-Update 二级索引导致的性能问题排查
chengang
390次阅读
2025-03-28 16:28:31
【活动】分享你的压箱底干货文档,三篇解锁进阶奖励!
墨天轮编辑部
359次阅读
2025-04-17 17:02:24
MySQL 9.3 正式 GA,我却大失所望,新特性亮点与隐忧并存?
JiekeXu
356次阅读
2025-04-15 23:49:58
3月“墨力原创作者计划”获奖名单公布
墨天轮编辑部
332次阅读
2025-04-15 14:48:05
云和恩墨杨明翰:安全生产系列之MySQL高危操作
墨天轮编辑部
309次阅读
2025-03-27 16:45:26
openHalo问世,全球首款基于PostgreSQL兼容MySQL协议的国产开源数据库
严少安
301次阅读
2025-04-07 12:14:29