Leetcode 178 分数排名

题目:178. 分数排名

我的解答

使用了MySQL提供的函数

1
2
3
SELECT score, DENSE_RANK() OVER(ORDER BY score DESC) AS 'rank'

FROM Scores;

因为别名rankrank函数冲突了,所以加个引号。

使用变量

SELECT score,
CAST((CASE
WHEN @prev = score THEN @curRank
WHEN @prev := score THEN @curRank := @curRank +1
WHEN score = 0 THEN @curRank := @curRank + 1
END) AS SIGNED) AS 'rank'
FROM scores,
(SELECT @curRank := 0, @prev := NULL) AS r
ORDER BY score DESC;

变量prev指向的是先前一行记录里的score,变量curRank是当前这个分数的排名。

这一段的描述可能不够准确:首先查询得到每一条记录的score并按降序排序,而后,从上到下,第一个score是4.00,设为1,第二个score也是4.00,也设为1,第三个是3.85,设为1+1=2,依次类推。根据我所了解的,SQL的执行顺序中,ORDER BY是在SELECT执行之后才执行的。但是,上述过程很明显利用了排序后的结果,所以这一点我就很困惑。如果用主查询和子查询来理解,主查询执行完之后,对于返回的每一行结果再执行子查询,似乎可行,但代码中的子查询是出现在FROM后面的,而条件判断是主查询里面的。这里我依旧很困惑。

(SELECT @curRank := 0, @prev := NULL) AS r,是一个子查询,可以看做是为这两个变量设定初始值。对于派生出来的表,必须指定别名(Every derived table must have its own alias)。这里指定了别名r。

cast(字段 as signed)将数据转换为整型,如果不使用这个函数,选出来的排名有双引号。

参考:MySQL自定义变量的语法,Case When语法及用法 教你用SQL实现统计排名

使用自联结

SELECT a.score AS score,
COUNT(DISTINCT b.score) AS 'rank'
FROM scores AS a, scores AS b
WHERE a.score <= b.score
GROUP BY a.id
ORDER BY a.score DESC