LeetCode——Rank Scores

2022-10-14,

write a sql query to rank scores. if there is a tie between two scores, both should have the same ranking. note that after a tie, the next ranking number should be the next consecutive integer value. in other words, there should be no "holes" between ranks.

+----+-------+
| id | score |
+----+-------+
| 1  | 3.50  |
| 2  | 3.65  |
| 3  | 4.00  |
| 4  | 3.85  |
| 5  | 4.00  |
| 6  | 3.65  |
+----+-------+
for example, given the above scores table, your query should generate the following report (order by highest score):

+-------+------+
| score | rank |
+-------+------+
| 4.00  | 1    |
| 4.00  | 1    |
| 3.85  | 2    |
| 3.65  | 3    |
| 3.65  | 3    |
| 3.50  | 4    |
+-------+------+

此题,其本质就是赋值行号(需要注意分数相同的情景).

在实践过程中,初版答案如下所示:

# write your mysql query statement below
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 a.score desc;

此处,使用select count来统计行号,注意使用distinct来区分相同分数.
但是,此解题方案的效率较差,sql运行肯定是越快越好.
因此,在sql中引入变量来赋值行号,以替代耗时的select count操作.

# write your mysql query statement below
select 
    score,
    @row := @row + (@pre <> (@pre := score)) as rank
from scores, (select @row := 0, @pre := -1) t
order by score desc;

此处,查询是在scores与临时表之间进行cross join.
此外,使用临时变量(@row,@pre)记录行号.
tips:

  • 通过@pre与当前score的比较,确定是否+1,需要注意mysql中的true/false0/1);
  • sql中,set/update语句中,=表示赋值;在set/update/select中,:=表示赋值,因此使用:=.

通过以上改进,mysql的运行效率得到了较大的提高.

《LeetCode——Rank Scores.doc》

下载本文的Word格式文档,以方便收藏与打印。