2009-04-25 33 views
1

這是我正在使用的一個真正的noobish MySQL查詢問題。MySQL在Group By查詢中選擇錯誤的列值

我在寫一個遊戲中有高分表。高分數據庫記錄了名稱,等級和分數。數據庫中有很多重複項。例如:

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分!我怎樣才能解決這個問題?

回答

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)...)。現在,對於讀取鮑勃的每一行,您將獲得他的最高等級(3),以及他在該等級(21)的最高分數。但是,這仍然給了我們無數的鮑勃行(例如,如果他有5行,你會得到5行鮑勃3 21)。爲了將其限制在最高分,我們需要在select語句中使用DISTINCT子句來僅返回唯一的行。

UPDATE:正確的SQL(不能在樂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 
+0

感謝您的解釋埃裏克 - 它對我來說是完全意義上的,但代碼並沒有工作,我不能發現問題在哪裏。現在代碼一直返回Bob的LOWEST級別的分數,而不是他的最高分數! 之前它似乎是數據庫中的第一個得分,這是不好的。所以這是好得多 - 只是不完美:) – 2009-04-25 03:25:50

+0

我認爲你需要在最後一行:GROUP BY h1.Name,h1.Level – bernie 2009-04-25 04:22:07

+0

你說得對 - 沒有複製它時,我粘貼它在。謝謝! – Eric 2009-04-25 05:12:53

1

這是有效的。

SELECT h1.Name,h1.Level,h1.Score
FROM高分H1
LEFT JOIN高分h2的ON h1.name = h2.name AND h1.level < h2.level
LEFT JOIN高分h3的ON h1.name = h3.name AND h1.level = h3.level和h1.score < h3.score
WHERE h2.id IS NULL和h3.id IS NULL

您正在尋找的水平/分對於該用戶沒有更高的等級,並且沒有更高的等級。

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; 

就個人而言,我覺得這是最容易理解,我的直覺是,這將是比較有效的數據庫來執行。

我喜歡上面的查詢最好,但只是踢...我覺得下面一個有趣的方式kludgey。假設分數不能超過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;