这是我遇到的一个真正的noobish MySQL查询问题。
我在写作的游戏中有一个高分表。高分DB记录了所获得的名称,级别和分数。 db中有许多接近重复的内容。例如:
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
然而,这并不是很有效。 “得分”字段输出似乎总是从组中随机拉出,而不是取得达到的最高级别的相应分数。例如:
Name | Level | Score
Bob 3 41
Joe 2 40
鲍勃从未在3级获得41分!我该如何解决这个问题?
答案 0 :(得分: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的两条记录)。
那么,我们如何解决这个问题呢?你需要做一个子查询来额外过滤你的结果,这就是那个(选择max(score)...)。现在,对于读取Bob的每一行,您将获得他的最高等级(3),以及他在该等级的最高分数(21)。但是,这仍然给了我们许多鲍勃的行(例如 - 如果他有5行,你将得到5行鲍勃3 21)。要将此限制为仅最高分,我们需要在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
答案 1 :(得分:1)
这很有效。
SELECT h1.Name,h1.Level,h1.Score
来自高分榜h1
LEFT JOIN highscores h2 ON h1.name = h2.name AND h1.level&lt; h2.level
LEFT JOIN highscores h3 ON h1.name = h3.name AND h1.level = h3.level AND h1.score&lt; h3.score
WHERE h2.id IS NULL和h3.id IS NULL
您正在寻找该用户没有更高级别的级别/分数,并且没有该级别的更高分数。
答案 2 :(得分: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;