Mysql 常见排名实现

本文涉及的产品
RDS DuckDB + QuickBI 企业套餐,8核32GB + QuickBI 专业版
RDS AI 助手,专业版
RDS Agent(兼容OpenClaw),2核4GB
简介: Mysql 常见排名实现

1.知识和数据准备

MySQL的排名函数为我们提供了强大而灵活的方式来处理数据的排序和排名,通过Mysql官网学习整理如下:

最常见的就是学校学生成绩排名,想要查看学生语文成绩排名情况,结果展示如下:

select student_id,
       subject,
       score,
       row_number() over (partition by subject order by score desc) `row_number`,
       rank() over (partition by subject order by score desc)       `rank`,
       dense_rank() over (partition by subject order by score desc) `dense_rank`
from student_subject_scroe
where subject = 'China';
+------------+---------+-------+------------+------+------------+
| student_id | subject | score | row_number | rank | dense_rank |
+------------+---------+-------+------------+------+------------+
| 01         | China   |    97 |          1 |    1 |          1 |
| 02         | China   |    96 |          2 |    2 |          2 |
| 03         | China   |    96 |          3 |    2 |          2 |
| 04         | China   |    96 |          4 |    2 |          2 |
| 05         | China   |    92 |          5 |    5 |          3 |
| 06         | China   |    90 |          6 |    6 |          4 |
+------------+---------+-------+------------+------+------------+

数据准备:

create table student_subject_scroe
(
    student_id varchar(255) comment '学生编号',
    subject    varchar(255) comment '课程名称',
    score      int comment '分数'
);
insert into dwd.student_subject_scroe (student_id, subject, score) values ('01', 'english', 89);
insert into dwd.student_subject_scroe (student_id, subject, score) values ('01', 'math', 61);
insert into dwd.student_subject_scroe (student_id, subject, score) values ('01', 'china', 97);
insert into dwd.student_subject_scroe (student_id, subject, score) values ('02', 'english', 87);
insert into dwd.student_subject_scroe (student_id, subject, score) values ('02', 'math', 53);
insert into dwd.student_subject_scroe (student_id, subject, score) values ('02', 'china', 96);
insert into dwd.student_subject_scroe (student_id, subject, score) values ('03', 'english', 87);
insert into dwd.student_subject_scroe (student_id, subject, score) values ('03', 'math', 53);
insert into dwd.student_subject_scroe (student_id, subject, score) values ('03', 'china', 96);
insert into dwd.student_subject_scroe (student_id, subject, score) values ('04', 'english', 84);
insert into dwd.student_subject_scroe (student_id, subject, score) values ('04', 'math', 52);
insert into dwd.student_subject_scroe (student_id, subject, score) values ('04', 'china', 96);
insert into dwd.student_subject_scroe (student_id, subject, score) values ('05', 'english', 74);
insert into dwd.student_subject_scroe (student_id, subject, score) values ('05', 'math', 47);
insert into dwd.student_subject_scroe (student_id, subject, score) values ('05', 'china', 92);
insert into dwd.student_subject_scroe (student_id, subject, score) values ('06', 'english', 73);
insert into dwd.student_subject_scroe (student_id, subject, score) values ('06', 'math', 40);
insert into dwd.student_subject_scroe (student_id, subject, score) values ('06', 'china', 90);

2.顺序排序,不重复不间断的连续序号

需求:想要查看每门学科对应的成绩排名,排名不重复不间断

-- 使用row_number()函数实现
select student_id,
       subject,
       score,
       row_number() over (partition by subject order by score desc) `row_number`
from student_subject_scroe;
-- 通过定义变量实现
select student_id,
       subject,
       score,
       `row_number`
from (select a.student_id,
             a.subject,
             a.score,
             if(@pre_subject = a.subject,   -- 排序后,判断上一行的学科是否等于当前行
        @row_num := @row_num + 1,   -- 是,返回@row_num+1,并且再次赋值给该变量@row_num
        @row_num := 1) `row_number`,-- 否,重置@row_num变量为1
             @pre_subject := a.subject      -- 将当前行的学科赋值给@pre_subject
      from student_subject_scroe as a,
           (select @pre_subject := null, @row_num := 0) b -- 临时表b,定义初始变量
      order by subject, score desc  -- 根据学科,分数降序排
) as c;

row_number()使用直接根据学科分组,分数降序即可得到结果;

通过定义变量实现,可以理解为select是一行行记录查询出来的,弄清变量的赋值的先后顺序,每行该变量的值,那么就清楚了。

3.并列排名,会跳过重复的序号

需求:想要查看每门学科对应的成绩排名,排名会重复间断

-- 使用rank()函数实现
select student_id,
       subject,
       score,
       rank() over (partition by subject order by score desc)       `rank`
from student_subject_scroe;
-- 通过定义变量实现
select student_id,
       subject,
       score,
       `rank`
from (select a.student_id,
             a.subject,
             a.score,
             IF(@pre_subject = a.subject,     -- 排序后,判断上一行的学科是否等于当前行
                @row_num := @row_num + 1,     -- 是,返回@row_num+1,并且再次赋值给该变量@row_num
                @row_num := 1) `row_number`, -- 否,重置@row_num变量为1
             IF(@pre_subject = a.subject,     -- 排序后,判断上一行的学科是否等于当前行
                IF(@pre_score = a.score,      -- 上一行学科等于当前行,则判断上一行分数是否等于当前行分数
           @cur_rank,                 -- 分数相等,则输出@cur_rank
           @cur_rank := @row_num),  -- 分数不等,则输出`row_number`的@row_num,注意要赋值给@cur_rank,给下一行引用
                @cur_rank := 1) `rank`,       -- 学科不等,则重置@cur_rank变量为1
             @pre_subject := a.subject,       -- 将当前行的学科赋值给@pre_subject
             @pre_score := a.score            -- 将当前行的分数赋值给@pre_score
      from student_subject_scroe as a,
           (select @pre_subject := null,@pre_score := null,@cur_rank := 0,@row_num := 0) b -- 临时表b,定义初始变量
      order by subject, score desc) as c -- 根据学科,分数降序排
;     

rank()使用直接根据学科分组,分数降序即可得到结果;

通过定义变量实现,借助根据步骤2中顺序排名,不重复跳跃的序号的变量实现,弄清变量的赋值的先后顺序,每行该变量的值,那么也就处理了。

4.并列排序,有重复间断的序号

需求:想要查看每门学科对应的成绩排名,排名重复不间断

-- 使用dense_rank()函数实现
select student_id,
       subject,
       score,
       dense_rank() over (partition by subject order by score desc) `dense_rank`
from student_subject_scroe;
-- 通过定义变量实现
select student_id,
       subject,
       score,
       `rank`
from (select a.student_id,
             a.subject,
             a.score,
             IF(@pre_subject = a.subject,      -- 排序后,判断上一行的学科是否等于当前行
                IF(@pre_score = a.score,       -- 上一行学科等于当前行,则判断上一行分数是否等于当前行分数
           @cur_rank,                  -- 分数相等,则输出@cur_rank
           @cur_rank := @cur_rank + 1),-- 分数不等,则输出@cur_rank+1,注意要赋值给@cur_rank,给下一行引用
                @cur_rank := 1) `rank`,
             @pre_subject := a.subject,        -- 将当前行的学科赋值给@pre_subject
             @pre_score := a.score             -- 将当前行的分数赋值给@pre_score
      from student_subject_scroe as a,
           (select @pre_subject := null,@pre_score := null,@cur_rank := 0) b
      order by subject, score desc) as c       -- 根据学科,分数降序排
;

dense_rank()使用直接根据学科分组,分数降序即可得到结果;

通过定义变量实现,理解了步骤2和步骤3的排名实现,这也就简单了。

可以发现用排序函数特别简单,Mysql 8.0 之后的版本有窗口函数,之前的版本没有,所以赶紧下载新版本用起来。

相关实践学习
每个IT人都想学的“Web应用上云经典架构”实战
本实验从Web应用上云这个最基本的、最普遍的需求出发,帮助IT从业者们通过“阿里云Web应用上云解决方案”,了解一个企业级Web应用上云的常见架构,了解如何构建一个高可用、可扩展的企业级应用架构。
MySQL数据库入门学习
本课程通过最流行的开源数据库MySQL带你了解数据库的世界。   相关的阿里云产品:云数据库RDS MySQL 版 阿里云关系型数据库RDS(Relational Database Service)是一种稳定可靠、可弹性伸缩的在线数据库服务,提供容灾、备份、恢复、迁移等方面的全套解决方案,彻底解决数据库运维的烦恼。 了解产品详情: https://www.aliyun.com/product/rds/mysql 
相关文章
|
关系型数据库 MySQL
|
SQL 关系型数据库 MySQL
MySQL实现简单排名
MySQL实现简单排名
149 0
|
SQL JSON NoSQL
一起来聊聊MySQL 8.0 的特性及排名可好?
还在等什么,快来一起讨论关注吧,公众号【八点半技术站】,欢迎加入社群
一起来聊聊MySQL 8.0 的特性及排名可好?
|
SQL 关系型数据库 MySQL
MySQL实现排名
MySQL实现排名
364 0
|
SQL 关系型数据库 MySQL
一文解决所有MySQL分类排名问题
对数据库中的记录依据某个字段进行排序是一种常见需求,虽然简单的Order by可以胜任,但如果想要输出具体的排名却难以直接实现。如果再考虑重复排名或者分类排名,那么情况就更为复杂。 本文介绍4种分类排名方式:子查询、自连接、自定义变量以及MySQL8.0窗口函数。
752 0
一文解决所有MySQL分类排名问题
|
关系型数据库 MySQL
MYSQL实现排名函数RANK,DENSE_RANK和ROW_NUMBER
本文介绍了MYSQL实现排名函数RANK,DENSE_RANK和ROW_NUMBER
393 0
|
关系型数据库 MySQL 计算机视觉
|
关系型数据库 MySQL

推荐镜像

更多