【问题标题】:Getting multiple maxes of summed values获得多个最大值的总和
【发布时间】:2017-11-23 19:02:39
【问题描述】:

考虑这个示例数据:

+----------+------+--------+-----------------+
| username | qnum | qvalue | date            |
+----------+------+--------+-----------------+
| Linda    | 1    | 2      | 11/14/2017 7:25 |
+----------+------+--------+-----------------+
| Fred     | 1    | 1      | 11/23/2017 7:59 |
+----------+------+--------+-----------------+
| Brian    | 5    | 2      | 11/17/2017 7:25 |
+----------+------+--------+-----------------+
| Sandra   | 6    | 1      | 11/25/2017 7:26 |
+----------+------+--------+-----------------+
| Tom      | 6    | 1      | 11/22/2017 7:32 |
+----------+------+--------+-----------------+
| Paul     | 6    | 1      | 11/22/2017 7:36 |
+----------+------+--------+-----------------+
| Andrew   | 7    | 2      | 11/23/2017 7:37 |
+----------+------+--------+-----------------+
| Luke     | 3    | 1      | 11/23/2017 8:03 |
+----------+------+--------+-----------------+
| William  | 8    | 1      | 11/23/2017 8:03 |
+----------+------+--------+-----------------+
| Linda    | 9    | 2      | 11/15/2017 8:03 |
+----------+------+--------+-----------------+
| Brian    | 3    | 2      | 11/17/2017 8:04 |
+----------+------+--------+-----------------+
| Joan     | 9    | 1      | 11/23/2017 8:04 |
+----------+------+--------+-----------------+
| Chris    | 8    | 1      | 11/23/2017 8:04 |
+----------+------+--------+-----------------+
| Kim      | 8    | 1      | 11/15/2017 8:04 |
+----------+------+--------+-----------------+

我正在尝试找到上周 qvalue 总和最高的人。我可以使用以下 SQL 获取此信息,但我的问题是,如果多个用户获得最高分,那么它不会显示他们的两个名字,因为我使用的是 LIMIT 函数。有没有办法同时使用 max 和 sum 来获得所需的结果?期望的结果是 Linda 和 Brian 都列出的结果集,因为上周他们的总分均为 4 并且并列。

SELECT username, SUM(qvalue) AS score FROM trivia_scoreboard 
WHERE `date` >= CURDATE() - INTERVAL DAYOFWEEK(CURDATE())+6 DAY AND `date` < CURDATE() - INTERVAL DAYOFWEEK(CURDATE())-1 DAY
GROUP BY username
ORDER BY score DESC
LIMIT 1

【问题讨论】:

  • MariaDB 的版本是多少?最新的支持 CTE。
  • @PaulSpiegel mysql Ver 15.1 Distrib 5.5.56-MariaDB,适用于 Linux (x86_64)
  • 请参阅mysql.rjweb.org/doc.php/groupwise_max,了解使用和不使用 dups 获得 groupwise max 的有效方法。

标签: mysql sql mariadb


【解决方案1】:

您必须将该查询与获取每个人总数的查询结合起来。

SELECT t1.*
FROM (
    SELECT username, SUM(qvalue) AS score FROM trivia_scoreboard 
    WHERE `date` >= CURDATE() - INTERVAL DAYOFWEEK(CURDATE())+6 DAY AND `date` < CURDATE() - INTERVAL DAYOFWEEK(CURDATE())-1 DAY
    GROUP BY username
) AS t1
JOIN (
    SELECT SUM(qvalue) AS score FROM trivia_scoreboard 
    WHERE `date` >= CURDATE() - INTERVAL DAYOFWEEK(CURDATE())+6 DAY AND `date` < CURDATE() - INTERVAL DAYOFWEEK(CURDATE())-1 DAY
    GROUP BY username
    ORDER BY score DESC
    LIMIT 1
) AS t2 ON t1.score = t2.score

DEMO

【讨论】:

  • 第一个子查询中不需要 ORDER BY。但是我会使用 HAVING 子句而不是 JOIN。
  • 去掉了ORDER BY,但不知道如何使用HAVING。你不能说HAVING score = MAX(score)
  • having score = (original query without username with LIMIT 1) - 就像 Gordons 的回答一样。但我对这两个答案都很好。
  • @PaulSpiegel 我认为当您在这样的比较中使用子查询时,MySQL 不允许 LIMIT
  • 即使在 WHERE 子句中我也经常使用它 :-) .. sqlfiddle.com/#!9/89e7d/5
【解决方案2】:

您也可以使用having

SELECT ts.username, SUM(ts.qvalue) AS score
FROM trivia_scoreboard fs
WHERE ts.`date` >= CURDATE() - INTERVAL DAYOFWEEK(CURDATE())+6 DAY AND 
      ts.`date` < CURDATE() - INTERVAL DAYOFWEEK(CURDATE())-1 DAY
GROUP BY username
HAVING score = (SELECT SUM(ts2.qvalue) as score
                FROM trivia_scoreboard ts2
                WHERE ts2.`date` >= CURDATE() - INTERVAL DAYOFWEEK(CURDATE())+6 DAY AND 
                      ts2.`date` < CURDATE() - INTERVAL DAYOFWEEK(CURDATE())-1 DAY
                GROUP BY username
                ORDER BY score DESC
                LIMIT 1
               );

这个和使用join 的版本之间的区别真的是一个品味问题。由于有关聚合如何在大量数据上扩展的详细信息,这可能会具有稍微更好的性能。

【讨论】:

  • 这个答案也解决了我的问题,我接受了Barmar的答案只是因为他先回答了。
  • @Tibblez 。 . .我赞成 Barmar's,因为它同样正确。在某些情况下,一个版本会优于另一个版本。
  • 最后不需要ORDER BY score DESC,因为每个人的分数都一样(我也错误地将其保留在我的原始答案中)。
  • 我希望我们的两个查询会产生相同的执行计划,但是 MySQL 的方式是神秘的。 :)
  • @Barmar 。 . .实际上,我认为您在这种情况下是对的。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2019-11-21
  • 2019-03-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多