MySQL分数排名
Posted willem_chen
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了MySQL分数排名相关的知识,希望对你有一定的参考价值。
mysql分数排名
SQL架构
Create table If Not Exists Scores (Id int, Score DECIMAL(3,2));
Truncate table Scores
insert into Scores (Id, Score) values ('1', '3.5');
insert into Scores (Id, Score) values ('2', '3.65');
insert into Scores (Id, Score) values ('3', '4.0');
insert into Scores (Id, Score) values ('4', '3.85');
insert into Scores (Id, Score) values ('5', '4.0');
insert into Scores (Id, Score) values ('6', '3.65');
题目描述
编写一个 SQL 查询来实现分数排名。
如果两个分数相同,则两个分数排名(Rank)相同。请注意,平分后的下一个名次应该是下一个连续的整数值。换句话说,名次之间不应该有“间隔”。
+----+-------+
| Id | Score |
+----+-------+
| 1 | 3.50 |
| 2 | 3.65 |
| 3 | 4.00 |
| 4 | 3.85 |
| 5 | 4.00 |
| 6 | 3.65 |
+----+-------+
例如,根据上述给定的 Scores 表,你的查询应该返回(按分数从高到低排列):
+-------+------+
| Score | Rank |
+-------+------+
| 4.00 | 1 |
| 4.00 | 1 |
| 3.85 | 2 |
| 3.65 | 3 |
| 3.65 | 3 |
| 3.50 | 4 |
+-------+------+
重要提示:对于 MySQL 解决方案,如果要转义用作列名的保留字,可以在关键字之前和之后使用撇号。
例如 `Rank`
题解
答1:Mysql比较好理解的一种写法
对于a表中的每一个分数score,找出b表中有多少个大于或等于该分数的不同的分数,然后按降序排列
select
a.Score as score ,
(select count(distinct b.Score) from Scores b where b.Score >=a.Score) as rank
from Scores a order by Score DESC;
+-------+------+
| score | rank |
+-------+------+
| 4.00 | 1 |
| 4.00 | 1 |
| 3.85 | 2 |
| 3.65 | 3 |
| 3.65 | 3 |
| 3.50 | 4 |
+-------+------+
6 rows in set (0.00 sec)
答2
select s1.Score,
(
select count(distinct s2.Score) from Scores s2 where s2.Score > s1.Score )
+1 `Rank` from Scores s1 order by Score DESC;
+-------+------+
| Score | Rank |
+-------+------+
| 4.00 | 1 |
| 4.00 | 1 |
| 3.85 | 2 |
| 3.65 | 3 |
| 3.65 | 3 |
| 3.50 | 4 |
+-------+------+
6 rows in set (0.00 sec)
答3:临时变量 + 联查 实现
我看题解了里面大部分都是用了 DENSE_RANK() 函数实现的,不过 mysql 5.x 版本好像不支持,所以用临时变量加联查的方式来实现感觉也不错,虽然通不过本题,但是应该是正确的做法,我的mysql版本是 5.6.45
第一步:先查分数对应的排名
select
@Rank := @Rank + 1 AS Rank,
s.Score
from
( select @Rank := 0 ) m,
( select Score from Scores group by Score desc) s
+------+-------+
| Rank | Score |
+------+-------+
| 1 | 4.00 |
| 2 | 3.85 |
| 3 | 3.65 |
| 4 | 3.50 |
+------+-------+
4 rows in set, 1 warning (0.00 sec)
第二步:和原有的Scores表联查,再根据rank字段排序即可
select s.Score, r.Rank
from Scores s
left join
(
select
@Rank := @Rank + 1 AS Rank,
s.Score
from
( select @Rank := 0 ) m,
( select Score from Scores group by Score desc) s
) r
on s.Score = r.Score
order by r.Rank;
+-------+------+
| Score | Rank |
+-------+------+
| 4.00 | 1 |
| 4.00 | 1 |
| 3.85 | 2 |
| 3.65 | 3 |
| 3.65 | 3 |
| 3.50 | 4 |
+-------+------+
6 rows in set, 1 warning (0.00 sec)
( select @Rank := 0 ) m, 这个表,是在给临时变量赋初始值。
知识点
MySQL的@与@@区别
@x 是 用户自定义的变量 (User variables are written as @var_name)
@@x 是 global或session变量 (@@global @@session )
@@查看全局变量:
select @@log_error;
@设置全局变量值:
mysql> SET @t1=0, @t2=0, @t3=0;
mysql> SELECT @t1:=(@t2:=1)+@t3:=4,@t1,@t2,@t3;
mysql中:=和=的区别
=
只有在 set 和 update 时才是和 := 一样,赋值的作用,其它都是等于的作用。鉴于此,用变量实现行号时,必须用:=
:=
不只在set和update时时赋值的作用,在select也是赋值的作用。
@num:=@num+1,:=是赋值的作用,所以,先执行@num+1,然后再赋值给@num,所以能正确实现行号的作用。
@num=@num+1,此时=是等于的作用,@num不等于@num+1,所以始终返回0,如果改为@num=@num,始终返回1了。mysql数据库中,用1表示真,0表示假。
以上是关于MySQL分数排名的主要内容,如果未能解决你的问题,请参考以下文章