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/false
为0/1
); - 在
sql
中,set/update
语句中,=
表示赋值;在set/update/select
中,:=
表示赋值,因此使用:=
.
通过以上改进,mysql
的运行效率得到了较大的提高.
PS:
如果您觉得我的文章对您有帮助,请关注我的微信公众号,谢谢!