MySQL跨多列排名

Posted

技术标签:

【中文标题】MySQL跨多列排名【英文标题】:MySQL rank across multiple columns 【发布时间】:2017-01-20 14:52:13 【问题描述】:

我们有一个包含以下数据的 mysql 表(结果)

|nid|uid|score|duration

在这张表中,我们有多个测验的结果, 我们需要提出一个查询,该查询将为我们提供每个测验的用户排名输出。

排名必须基于最高分到最低分,如果分数与最低持续时间和最高持续时间相关。我们目前有这个查询:

  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

【问题讨论】:

已解决:缺少@prevRank := score + duration 如果下一行的分数和时长不同但总和与上一行相同怎么办? 尝试用@incRank := @curRank + 1,替换@incRank := @incRank + 1, Jan 你的建议仍然输出相同的结果 @GurV 这是一个好点,你有什么建议来解决这个问题吗? 【参考方案1】:

您需要为列使用单独的变量。另外,在子查询中进行排序,然后应用交叉连接并查找排名等。

试试这个:

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

【讨论】:

我真的很喜欢这个并且效果很好,我添加了一个 WHERE nid = 1,因为在同一个表格中有多个测验结果是必需的 @GHaddon 已更新。看起来怎么样? 我正在寻找同样的东西,但我希望排名数线性上升。这看起来如何。提前谢谢。

以上是关于MySQL跨多列排名的主要内容,如果未能解决你的问题,请参考以下文章

熊猫按多列排名

Presto SQL - 对多列的多个条件进行排名

Excel小tips - 如何实现多列成绩统一排名

MySQL实现排名并查询指定用户排名功能,并列排名功能

mysql使用rownum方式,实现部门排名和公司排名

mysql使用rownum方式,实现部门排名和公司排名