查找用户最高分数和相关详细信息

时间:2010-03-28 22:51:44

标签: mysql grouping max

我有一张桌子,用户可在其中存储有关所述分数的分数和其他信息(例如有关分数的注释或所用的时间等)。我想要一个mysql查询,它可以找到每个用户的个人最佳分数,以及相关的笔记和时间等。

我试图使用的是这样的:

SELECT *,MAX(得分)FROM表GROUP BY(用户)

问题在于,尽管您可以从该查询[MAX(得分)]中获得个人最佳用户,但返回的注释和时间等与最高分数无关,而是与不同的分数(特别是包含的分数)相关联在*)。有没有办法可以编写一个选择我想要的查询?或者我必须在PhP中手动完成吗?

3 个答案:

答案 0 :(得分:2)

我假设你每个玩家只想要一个结果,即使他们已经多次获得相同的最高分。我也假设你希望每个球员第一次在重复的情况下获得个人最好的成绩。

有几种方法可以做到这一点。这是一种特定于MySQL的方式:

SELECT user, scoredate, score, notes FROM (
    SELECT *, @prev <> user AS is_best, @prev := user
    FROM table1, (SELECT @prev := -1) AS vars
    ORDER BY user, score DESC, scoredate
) AS T1
WHERE is_best

这是一种使用普通SQL的更通用的方法:

SELECT T3.* FROM table1 AS T3
JOIN (
    SELECT T1.user, T1.score, MIN(scoredate) AS scoredate
    FROM table1 AS T1
    JOIN (SELECT user, MAX(score) AS score FROM table1 GROUP BY user) AS T2
    ON T1.user = T2.user AND T1.score = T2.score
    GROUP BY T1.user
) AS T4
ON T3.user = T4.user AND T3.score = T4.score AND T3.scoredate = T4.scoredate

结果:

1, '2010-01-01 17:00:00', 50, 'Much better'
2, '2010-01-01 14:00:00', 100, 'Perfect score'

我用来测试的测试数据:

CREATE TABLE table1 (user INT NOT NULL, scoredate DATETIME NOT NULL, score INT NOT NULL, notes NVARCHAR(100) NOT NULL);
INSERT INTO table1 (user, scoredate, score, notes) VALUES
(1, '2010-01-01 12:00:00', 10, 'First attempt'),
(1, '2010-01-01 17:00:00', 50, 'Much better'),
(1, '2010-01-01 22:00:00', 30, 'Time for bed'),
(2, '2010-01-01 14:00:00', 100, 'Perfect score'),
(2, '2010-01-01 16:00:00', 100, 'This is too easy');

答案 1 :(得分:1)

SELECT *
FROM table t
ORDER BY t.score DESC
GROUP BY t.user
LIMIT 1

附注:最好指定字段而不是使用SELECT *

答案 2 :(得分:1)

您可以加入子查询,如下例所示:

SELECT   t.*,
         sub_t.max_score
FROM     table t
JOIN     (SELECT   MAX(score) as max_score,
                   user
          FROM     table
          GROUP BY user) sub_t ON (sub_t.user = t.user AND
                                   sub_t.max_score = t.score);

以上查询可以解释如下。它始于:

SELECT t.* FROM table t;

...这本身就会列出表格的所有内容。目标是仅保留表示特定用户的最大分数的行。因此,如果我们有以下数据:

+------------------------+
| user | score |  notes  | 
+------+-------+---------+
|    1 |    10 |  note a |
|    1 |    15 |  note b |    
|    1 |    20 |  note c |
|    2 |     8 |  note d |
|    2 |    12 |  note e |
|    2 |     5 |  note f |
+------+-------+---------+

......我们本来想保留“note c”和“note e”行。

要查找我们要保留的行,我们只需使用:

SELECT MAX(score), user FROM table GROUP BY user;

请注意,我们无法从上述查询中获取notes属性,因为正如您已经注意到的那样,您不会获得未使用aggregate function汇总的字段的预期结果,例如MAX() GROUP BY子句的一部分。有关此主题的进一步阅读,您可能需要检查:

现在我们只需要保留第一个查询中与第二个查询匹配的行。我们可以使用INNER JOIN

执行此操作
...
JOIN     (SELECT   MAX(score) as max_score,
                   user
          FROM     table
          GROUP BY user) sub_t ON (sub_t.user = t.user AND
                                   sub_t.max_score = t.score);

子查询的名称为sub_t。它是具有个人最佳分数的所有用户的集合。 ON的{​​{1}}子句将限制应用于相关字段。请记住,我们只想保留属于此子查询的行。