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);
需求:想要查看每门学科对应的成绩排名,排名不重复不间断
-- 使用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是一行行记录查询出来的,弄清变量的赋值的先后顺序,每行该变量的值,那么就清楚了。
需求:想要查看每门学科对应的成绩排名,排名会重复间断
-- 使用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中顺序排名,不重复跳跃的序号的变量实现,弄清变量的赋值的先后顺序,每行该变量的值,那么也就处理了。
需求:想要查看每门学科对应的成绩排名,排名重复不间断
-- 使用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 之后的版本有窗口函数,之前的版本没有,所以赶紧下载新版本用起来。