使用GROUP BY时选择特定行

时间:2014-04-21 19:32:19

标签: mysql sql

我有以下SQL表,用于跟踪用户在特定时间点的分数。用户每天可以获得多个分数。

+-------+------------+-------+-----+
| user  | date       | score | ... |
+-------+------------+-------+-----+
| bob   | 2014-04-19 | 100   | ... |
| mary  | 2014-04-19 | 100   | ... |
| alice | 2014-04-20 | 100   | ... |
| bob   | 2014-04-20 | 110   | ... |
| bob   | 2014-04-20 | 125   | ... |
| mary  | 2014-04-20 | 105   | ... |
| bob   | 2014-04-21 | 115   | ... |
+-------+------------+-------+-----+

鉴于特定用户(让我们说bob),如何生成每个用户得分的报告,但只使用每天提交的最高得分?< / strong>(获得分数最高的特定行也很重要,而不仅仅是最高分)

SELECT * FROM `user_score` WHERE `user` = 'bob' GROUP BY `date`

是我建立的基本查询。它产生以下结果集:

+-------+------------+-------+-----+
| user  | date       | score | ... |
+-------+------------+-------+-----+
| bob   | 2014-04-19 | 100   | ... |
| bob   | 2014-04-20 | 110   | ... |
| bob   | 2014-04-21 | 115   | ... |
+-------+------------+-------+-----+

bob 125的{​​{1}}得分较高。我试过用2014-04-20

来纠正这个问题
MAX(score)

返回当天的最高分,但不是得分最高的行。该行上的其他列值很重要,

SELECT *, MAX(score)  FROM `user_score` WHERE `user` = 'bob' GROUP BY `date`

最后,我试过

+-------+------------+-------+-----+------------+
| user  | date       | score | ... | max(score) |
+-------+------------+-------+-----+------------+
| bob   | 2014-04-19 | 100   | ... | 100        |
| bob   | 2014-04-20 | 110   | ... | 125        |
| bob   | 2014-04-21 | 115   | ... | 110        |
+-------+------------+-------+-----+------------+

但这会导致SELECT *, MAX(score) FROM `user_score` WHERE `user` = 'bob' AND score = MAX(score) GROUP BY `date` 无效使用。

编辑:

SQLFiddle:http://sqlfiddle.com/#!2/ee6a2

3 个答案:

答案 0 :(得分:4)

如果您想要所有字段,MySQL中最简单(也是最快)的方法是使用not exists

SELECT *
FROM `user_score` us
WHERE `user` = 'bob' AND
      NOT EXISTS (SELECT 1
                  FROM user_score us2
                  WHERE us2.`user` = us.`user` AND
                        us2.date = us.date AND
                        us2.score > us.score
                 );

这似乎是一种奇怪的方法。并且,我承认它是。它正在做的非常简单:“从user_score获取Bob的所有行,其中没有更高的分数(对于Bob)”。这相当于获得最高分的行。使用user_score(name, score)上的索引,这可能是执行所需操作的最有效方式。

答案 1 :(得分:2)

您可以使用JOIN

SELECT a.*
FROM `user_score` as a
INNER JOIN (SELECT `user`, `date`, MAX(score) MaxScore
            FROM `user_score` 
            GROUP BY `user`, `date`) as b
    ON a.`user` = b.`user`
    AND a.`date` = b.`date`
    AND a.score = b.MaxScore
WHERE a.`user` = 'bob' 

答案 2 :(得分:0)

一种选择是使用内联视图和JOIN操作。如果给定日期的多个行具有“高分”值,则此查询将返回所有行。 (如果(user,date,score)是唯一的,那么这不是问题。)

例如:

SELECT t.user
     , t.date
     , t.score
     , t.`...`
  FROM user_score t
  JOIN ( SELECT d.user
              , d.date
              , MAX(s.score) AS score
           FROM user_score d 
          WHERE d.user = 'bob'
          GROUP BY d.user, d.date
       ) s
    ON s.user  = t.user
   AND s.date  = t.date
   AND s.score = t.score