我们有一个包含以下数据的MySQL表(结果)
|nid|uid|score|duration
在此表中,我们得到了多个quizes的结果, 我们需要提出一个查询,它将为我们提供每个测验的用户排名输出。
排名必须基于最高得分到最低得分,并且如果得分是最低持续时间与最高持续时间相关联。我们目前有这个查询:
SELECT nid, uid, score, duration, rank FROM
(SELECT nid, uid, score, duration,
@curRank := IF(@prevRank = score + duration, @curRank, @incRank) AS rank,
@incRank := @incRank + 1,
@prevRank := score
FROM results p, (
SELECT @curRank :=0, @prevRank := NULL, @incRank := 1
) r WHERE nid = 1
ORDER BY score DESC, duration ASC) s
然而,如果出现并列分数和并列持续时间,则会给出不同的等级
输出
|nid|uid|score|duration|rank
|1 |1 |90 |100 |1
|1 |2 |90 |150 |2
|1 |3 |90 |150 |3
|1 |4 |80 |100 |4
|1 |5 |80 |200 |5
|1 |6 |70 |300 |6
期望输出
|nid|uid|score|duration|rank
|1 |1 |90 |100 |1
|1 |2 |90 |150 |2
|1 |3 |90 |150 |2
|1 |4 |80 |100 |4
|1 |5 |80 |200 |5
|1 |6 |70 |300 |6
答案 0 :(得分:2)
您需要为列使用单独的变量。此外,在子查询中进行排序,然后然后应用交叉连接并查找排名等。
试试这个:
SELECT
t.*,
@rank:=IF((@rn:=@rn + 1) IS NOT NULL,
IF(score = @lastscore
AND duration = @lastduration,
@rank,
IF((@lastscore:=score) IS NOT NULL
AND (@lastduration:=duration) IS NOT NULL,
@rn,
1)),
1) rank
FROM
(SELECT
*
FROM
results
WHERE nid = 1
ORDER BY score DESC , duration , uid) t
CROSS JOIN
(SELECT @rank:=0, @lastscore:=- 1, @lastduration:=- 1, @rn:=0) t2
您可能会想要在不同的列中单独指定值(就像您在问题中所做的那样)。 请注意,该方法可能无法正常工作,因为MySQL可能不会按照与列出的列相同的顺序进行分配。
MySQL documentation对此很清楚:
作为一般规则,您不应该为用户变量赋值 并在同一语句中读取值。你可能会得到 你期望的结果,但这不能保证。的顺序 涉及用户变量的表达式的评估是未定义的 可能会根据给定声明中包含的元素进行更改; 另外,这个顺序不保证是相同的 MySQL服务器的版本。在SELECT @ a,@ a:= @ a + 1,...,你可以 认为MySQL会首先评估@a然后做一个任务 第二。但是,更改语句(例如,通过添加 GROUP BY,HAVING或ORDER BY子句可能导致MySQL选择一个 执行计划具有不同的评估顺序。
演示 @ SQLFiddle