Mysql 常见排名实现

本文涉及的产品
RDS MySQL Serverless 基础系列,0.5-2RCU 50GB
RDS MySQL Serverless 高可用系列,价值2615元额度,1个月
简介: 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 之后的版本有窗口函数,之前的版本没有,所以赶紧下载新版本用起来。

相关实践学习
基于CentOS快速搭建LAMP环境
本教程介绍如何搭建LAMP环境,其中LAMP分别代表Linux、Apache、MySQL和PHP。
全面了解阿里云能为你做什么
阿里云在全球各地部署高效节能的绿色数据中心,利用清洁计算为万物互联的新世界提供源源不断的能源动力,目前开服的区域包括中国(华北、华东、华南、香港)、新加坡、美国(美东、美西)、欧洲、中东、澳大利亚、日本。目前阿里云的产品涵盖弹性计算、数据库、存储与CDN、分析与搜索、云通信、网络、管理与监控、应用服务、互联网中间件、移动服务、视频服务等。通过本课程,来了解阿里云能够为你的业务带来哪些帮助     相关的阿里云产品:云服务器ECS 云服务器 ECS(Elastic Compute Service)是一种弹性可伸缩的计算服务,助您降低 IT 成本,提升运维效率,使您更专注于核心业务创新。产品详情: https://www.aliyun.com/product/ecs
相关文章
|
10月前
|
关系型数据库 MySQL
|
7月前
|
SQL 关系型数据库 MySQL
MySQL实现简单排名
MySQL实现简单排名
25 0
|
SQL JSON NoSQL
一起来聊聊MySQL 8.0 的特性及排名可好?
还在等什么,快来一起讨论关注吧,公众号【八点半技术站】,欢迎加入社群
一起来聊聊MySQL 8.0 的特性及排名可好?
|
SQL 关系型数据库 MySQL
MySQL实现排名
MySQL实现排名
136 0
|
SQL 关系型数据库 MySQL
一文解决所有MySQL分类排名问题
对数据库中的记录依据某个字段进行排序是一种常见需求,虽然简单的Order by可以胜任,但如果想要输出具体的排名却难以直接实现。如果再考虑重复排名或者分类排名,那么情况就更为复杂。 本文介绍4种分类排名方式:子查询、自连接、自定义变量以及MySQL8.0窗口函数。
396 0
一文解决所有MySQL分类排名问题
|
关系型数据库 MySQL 计算机视觉
|
关系型数据库 MySQL
|
关系型数据库 MySQL
mysql 排名
#排名(原文) 需求:获取分类平均值的名次? 比如10个班级的平均分,按照班级名称排序,后面跟着名次。 记录表:table_test ; 字段:banji 班级;AvgS 平均分;pm 排名; 解决方法: FROM ( SELECT A.
852 0