我有下表(高分),
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 :(得分: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,不能在这个特定的构造中添加”。 (进一步阅读以了解原因)但是,如果目的是使得得分最高的游戏的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构造。顺便说一句,请在此页面上给予赞美,以便首先显示此类查询。
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结构的[现在相当长篇]解释的范围。
答案 1 :(得分:2)
SELECT中的每个字段(当存在GROUP BY子句时)必须是GROUP BY子句中的一个字段,或者是MAX,SUM,AVG等组函数。在代码中,userid
在技术上违反了它,但是以一种非常无害的方式(你可以使你的代码在技术上符合SQL GROUP BY gameid, userid
的标准;字段id
和date
受到更严重的违规行为 - 在一个GROUP BY
集合中会有许多ID和日期,并且您没有告诉如何从该集合中创建单个值(MySQL选择一个或多或少的随机数,更严格的SQL引擎可能更有助于给你一个错误。)
我知道您希望the
ID和日期对应于给定分组的最高分数,但这在您的代码中并不明确。你需要一个subselect或一个self-join来使它明确!
答案 2 :(得分: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'