2

这是我遇到的一个真正的 MySQL 查询问题。

我正在编写的游戏中有一张高分表。高分数据库记录名称、级别和达到的分数。数据库中有许多近乎重复的内容。例如:

Name | Level | Score | Timestamp (key)
Bob    2       41    | 1234567.890
Bob    3       15    | 1234568.890
Bob    3       20    | 1234569.890
Joe    2       40    | 1234561.890
Bob    3       21    | 1234562.890
Bob    3       21    | 1234563.890

我想返回一个“达到的最高水平”高分列表,输出类似于:

Name | Level | Score
Bob    3       21
Joe    2       40

我目前使用的 SQL 查询是:

SELECT *, MAX(level) as level 
FROM highscores 
GROUP BY name
ORDER BY level DESC, score DESC
LIMIT 5

然而,这并不完全奏效。“Score”字段输出似乎总是从组中随机抽取,而不是获取所达到的最高级别的相应分数。例如:

Name | Level | Score
Bob    3       41
Joe    2       40

Bob 在第 3 级时从未得到 41 分!我怎样才能解决这个问题?

4

3 回答 3

2

您需要使用子查询来提取分数。

select distinct
    name, 
    max(level) as level,
    (select max(score) from highscores h2 
        where h2.name = h1.name and h2.level = h1.level) as score
from highscores h1 
group by name 
order by level desc, score desc

干杯,

埃里克

让我感到恼火的是,当我发布答案时,我没有花时间解释为什么会出现这种情况,所以这里是:

当您拉回所有内容 (*),然后是最大级别时,您将得到的是按顺序排列的每条记录,加上一个带有最大级别的列。请注意,您没有按分数进行分组(这会给您 Bob 2 41 和 Bob 3 21 - 我们的朋友 Bob 的两条记录)。

那么,我们到底该如何解决这个问题呢?你需要做一个子查询来额外过滤你的结果,这就是 (select max(score)...) 是什么。现在,对于读取 Bob 的每一行,您将获得他的最高级别 (3),以及他在该级别的最高分数 (21)。但是,无论 Bob 有多少行,这仍然给了我们(例如,如果他有 5 行,您将得到 Bob 3 21 的 5 行)。要将其限制为仅最高分,我们需要在 select 语句中使用 DISTINCT 子句以仅返回唯一行。

更新:正确的 SQL(不能评论 le dorfier 的帖子):

SELECT h1.Name, h1.Level, MAX(h1.Score)
    FROM highscores h1
    LEFT OUTER JOIN highscores h2 ON h1.name = h2.name AND h1.level < h2.level
    LEFT OUTER JOIN highscores h3 ON h1.name = h3.name AND h2.level = h3.level AND h1.score < h3.score
    WHERE h2.Name IS NULL AND h3.Name IS NULL
    GROUP BY h1.Name, h1.Level
于 2009-04-25T02:50:43.873 回答
1

这是有效的。

SELECT h1.Name, h1.Level, h1.Score
FROM highscores h1
LEFT JOIN highscores h2 ON h1.name = h2.name AND h1.level < h2.level
LEFT JOIN highscores h3 ON h1.name = h3.name AND h1。 level = h3.level AND h1.score < h3.score 其中
h2.id 为空且 h3.id 为空

您正在寻找该用户没有更高级别的级别/分数,并且该级别没有更高的分数。

于 2009-04-25T03:42:51.890 回答
0

有趣的问题。这是另一个解决方案:

SELECT hs.name, hs.level, MAX(score) AS score
FROM highscores hs
INNER JOIN (
  SELECT name, MAX(level) AS level FROM highscores GROUP BY name
) hl ON hl.name = hs.name AND hl.level = hs.level
GROUP BY hs.name, hs.level;

就个人而言,我觉得这最容易理解,我的直觉是数据库执行起来会相对高效。

我最喜欢上面的查询,但只是为了好玩……我发现下面的查询以一种笨拙的方式很有趣。假设分数不能超过 99999...

SELECT name, level, score
FROM highscores hs
INNER JOIN (
  SELECT name, MAX(level * 100000 + score) AS hfactor
  FROM highscores GROUP BY name
) hf ON hf.hfactor = hs.level * 100000 + hs.score AND hf.name = hs.name;
于 2009-04-25T07:51:47.940 回答