MySQL:获得用户的最高分

Pra*_*ant 0 mysql sql

我有下表(高分),

id      gameid      userid      name      score      date
1       38          2345        A         100        2009-07-23 16:45:01
2       39          2345        A         500        2009-07-20 16:45:01
3       31          2345        A         100        2009-07-20 16:45:01
4       38          2345        A         200        2009-10-20 16:45:01
5       38          2345        A         50         2009-07-20 16:45:01
6       32          2345        A         120        2009-07-20 16:45:01
7       32          2345        A         100        2009-07-20 16:45:01
Run Code Online (Sandbox Code Playgroud)

现在在上述结构中,用户可以多次玩游戏,但我想显示特定用户的"游戏玩法".所以在游戏部分我不能展示多个游戏.因此,概念应该是如果用户玩了3次游戏,则应该显示具有最高分数的游戏.

我想要结果数据,如:

id      gameid      userid      name      score      date
2       39          2345        A         500        2009-07-20 16:45:01
3       31          2345        A         100        2009-07-20 16:45:01
4       38          2345        A         200        2009-10-20 16:45:01
6       32          2345        A         120        2009-07-20 16:45:01
Run Code Online (Sandbox Code Playgroud)

我尝试了以下查询,但它没有给我正确的结果:

SELECT id, 
       gameid, 
       userid, 
       date, 
       MAX(score) AS score 
  FROM highscores
 WHERE userid='2345' 
GROUP BY gameid 
Run Code Online (Sandbox Code Playgroud)

请告诉我这是什么问题?

谢谢

mjv*_*mjv 7

要求有点模糊/混乱但是这样的东西能满足需要吗?
(故意添加可能感兴趣的各种聚合).

SELECT gameid, 
       MIN(date) AS FirstTime, 
       MAX(date) AS LastTime,
       MAX(score) AS TOPscore.
       COUNT(*)  AS NbOfTimesPlayed 
FROM highscores
WHERE userid='2345' 
GROUP BY gameid
-- ORDER BY COUNT(*) DESC -- for ex. to have games played most at top
Run Code Online (Sandbox Code Playgroud)

编辑:关于将id列添加到SELECT列表
的新问题简短的答案是:"不,不能添加id,不能在此特定构造中添加".(进一步阅读以了解原因)但是,如果目的是使得具有最高分数的游戏的id,则可以使用子查询来修改查询以实现该目的.

正如Alex M在此页面上所解释的那样,SELECT列表中引用的所有列名称以及未在聚合函数(MAX,MIN,AVG,COUNT等)的上下文中使用的列名称必须包含在ORDER BY中条款.这种SQL语言规则的原因很简单,就是在收集结果列表的信息时,SQL可能会遇到这样一个列的多个值(列在SELECT但不是GROUP BY中),然后就不知道如何处理它了; SQL标准规定了一条错误消息,而不是做任何事情 - 可能有用但可能很愚蠢 - 这样,用户可以修改查询并明确表达他/她的目标.

在我们的特定情况下,我们可以在SELECT中添加id并将其添加到GROUP BY列表中,但是在这样做时,聚合发生的分组将是不同的:结果列表将包含与我们一样多的行id + gameid组合每行的聚合值将仅基于表中id和gameid具有相应值的记录(假设id是表中的PK,我们每个聚合得到一行,使得MAX()等无意义.

使用最高分包括与游戏相对应的id(以及可能的其他列)的方式是使用子查询.想法是子查询选择具有TOP得分的游戏(在给定的组中),并且主要查询选择此行的任何列,即使在子查询的组中没有(不可能)fieds -by构造.顺便说一句,请在此页面上给予信任以rexem首先显示此类型的查询.

SELECT H.id, 
       H.gameid, 
       H.userid, 
       H.name,
       H.score,
       H.date        
FROM highscores H
JOIN (
  SELECT M.gameid, hs.userid, MAX(hs.score) MaxScoreByGameUser
  FROM highscores H2
  GROUP BY H2.gameid, H2.userid
) AS M  
   ON M.gameid = H.gameid 
      AND M.userid = H.userid
      AND M.MaxScoreByGameUser = H.score
WHERE H.userid='2345' 
Run Code Online (Sandbox Code Playgroud)

关于上述查询的一些重要评论

  • 重复:如果用户玩过几个达到相同高分的游戏,则查询将生成那么多行.
  • 子查询的GROUP BY可能需要针对查询的不同用途进行更改.如果不是在每个用户的基础上搜索游戏的高分,我们想要绝对的高分,我们需要从GROUP BY中排除userid(这就是为什么我用一个长而明确的名字命名MAX的别名)
  • 为了提高效率,可以在子查询的[now absent] WHERE子句中添加userid ='2345'(除非MySQL的优化器非常智能,目前所有游戏+用户组合的所有高分都得到计算,因此我们只需要用户'2345'); 向下重复; 解; 变量.

有几种方法可以解决上面提到的问题,但这些方法似乎超出了关于GROUP BY结构的[现在相当长实]解释的范围.