2009-11-04 100 views
0

我有如下表(高分),MySQL的:获得最高分数用户

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 

现在,在上述结构中,用户可以玩游戏多次,但我想显示“已赛“由特定用户。所以在玩游戏的部分,我无法展示多款游戏。所以这个概念应该就像用户玩过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 

我尝试下面的查询,但它不是给我正确的结果:

SELECT id, 
     gameid, 
     userid, 
     date, 
     MAX(score) AS score 
    FROM highscores 
WHERE userid='2345' 
GROUP BY gameid 

请告诉我这将是这样做的查询?

感谢

+0

怎么样打破僵局的处理 - 当有2+记录相同的游戏和用户使用相同的高分?最近的日期? – 2009-11-04 05:22:36

+0

@rexem:在这种情况下,它将返回2中的1条记录。 – Prashant 2009-11-04 05:46:00

+0

@Prashant:是的,但是基于什么标准? – 2009-11-04 06:10:38

回答

2

你有你的SELECT(当GROUP BY子句存在的话)的每个字段必须在该组的领域中的任何一个BY子句,否则一组函数如MAX,SUM,AVG等等。在你的代码中,userid在技术上违反了这个规定,但是以非常无害的方式(你可以使你的代码在技术上符合SQL标准GROUP BY gameid, userid);字段iddate的违规情况更严重 - 在一个GROUP BY集合中将会有许多ID和日期,并且您不会告诉如何从该集合中创建单个值(MySQL选择一个或多或少的随机数据,更严格的SQL引擎可能会更有帮助地给你一个错误)。

我知道你想要the ID和日期对应于给定分组的最高分数,但这在代码中并不明确。你需要一个子选择或自联接才能使其变得明确!

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 

编辑:有关将ID列的SELECT列表
简短的回答是新的问题:“没有,身份证不能添加,没有这种特殊的构造内”。 (进一步阅读以了解原因)然而,如果意图使游戏的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分数的游戏(在给定的分组内),并且主要查询的SELECT选择该行的任何列,即使子查询的组中没有(不可能) - 构造。顺便说一句,在这个页面上给予奖励以便首先显示这种类型的查询。

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' 

关于上述

  • 重复查询的一些重要讲话:如果用户玩几个游戏,达到了同喜分数,查询会产生很多行。
  • GROUP BY的子查询可能需要更改为查询的不同用途。如果不是在每个用户的基础上搜索游戏的高分,我们希望获得绝对的高分,我们需要从GROUP BY中排除userid(这就是为什么我使用明确的长名称命名MAX的别名)
  • 为了提高效率,可以在子查询的[现在不存在] WHERE子句中添加userid ='2345'(除非MySQL的优化器非常聪明,目前所有游戏+用户组合的所有高分计算,因此我们只需要这些用户'2345');向下复制;解;变量。

有几种方法可以解决上面提到的问题,但是这些似乎超出了对GROUP BY结构[现在相当简单]的解释的范围。

+0

我们可以在此查询中包含“id”字段吗?当我包含它时,它不会给出正确的'id'? – Prashant 2009-11-04 07:25:35

+0

@Prashant:由于你是由gameid分组的,它不会是正确的'id'。因此'id'可能包含在分组 – 2009-11-04 07:35:28

+0

@Kevin Peno期间发现的最后一条序号记录,感谢您的快速响应。 @Prashant,我编辑了一个更长的解释,说明为什么使用子查询不能添加[在这个构造中]以及它是如何可能的。 – mjv 2009-11-04 15:55:22

1

用途:

SELECT t.id, 
     t.gameid, 
     t.userid, 
     t.name, 
     t.score, 
     t.date   
    FROM HIGHSCORES t 
    JOIN (SELECT hs.gameid, 
       hs.userid, 
       MAX(hs.score) 'max_score' 
      FROM HIGHSCORES hs 
     GROUP BY hs.gameid, hs.userid) mhs ON mhs.gameid = t.gameid 
             AND mhs.userid = t.userid 
             AND mhs.max_score = t.score 
WHERE t.userid = '2345'