2

これは、私が抱えている本当に初心者のMySQLクエリの問題です。

私が書いているゲームのハイスコア テーブルがあります。ハイスコ​​ア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 ポイントを獲得できませんでした! どうすればこれを修正できますか?

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 の 2 つのレコードです)。

では、これをどのように修正すればよいのでしょうか。結果をさらにフィルタリングするには、サブクエリを実行する必要があります。これが (select max(score)...) です。ここで、Bob を読み取る行ごとに、ボブの最大レベル (3) と、そのレベルでの最大スコア (21) を取得します。しかし、これでもボブが持っている行の数はわかります (たとえば、ボブが 5 行持っている場合、ボブ 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
WHERE h2.id IS NULL AND h3.id IS NULL

そのユーザーにとってより高いレベルがなく、そのレベルよりも高いスコアがないレベル/スコアを探しています。

于 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 に答える