MySQL Выбор неверного значения столбца в запросе Group By - PullRequest
1 голос
/ 25 апреля 2009

Вот настоящая проблема Noobish 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

Однако это не совсем работает. Вывод поля «Оценка» всегда кажется случайным образом извлеченным из группы, вместо того, чтобы брать соответствующий результат для самого высокого достигнутого уровня. Например:

Name | Level | Score
Bob    3       41
Joe    2       40

Боб никогда не набрал 41 очко на уровне 3! Как я могу это исправить?

Ответы [ 3 ]

2 голосов
/ 25 апреля 2009

Вам нужно будет использовать подзапрос, чтобы вывести счет.

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

Приветствия

Эрик

Меня раздражает, что я не нашел времени, чтобы объяснить, почему это так, когда я опубликовал ответ, поэтому вот так:

Когда вы вытягиваете все (*), а затем максимальный уровень, вы получаете последовательно каждую запись плюс столбец с максимальным уровнем. Обратите внимание, что вы не группируете по количеству очков (что дало бы вам Боба 2 41, а Боба 3 21 - две записи для нашего друга Боба).

Итак, как, чёрт возьми, мы это исправим? Вам необходимо выполнить подзапрос, чтобы дополнительно отфильтровать результаты, что и есть (выберите max (оценка) ...). Теперь для каждой строки, в которой читается Боб, вы получите его максимальный уровень (3) и максимальный балл на этом уровне (21). Но это все равно дает нам сколько угодно строк у Боба (например, если у него 5 рядов, вы получите 5 рядов Боба 3 21). Чтобы ограничить это только лучшим показателем, нам нужно использовать предложение 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 голос
/ 25 апреля 2009

Это эффективно.

ВЫБРАТЬ h1.Name, h1.Level, h1.Score
ОТ рекордов h1
СЛЕДУЮЩИЙ РЕЙТИНГ h2 ON h1.name = h2.name AND h1.level

СЛЕДУЮЩИЙ РЕЙТИНГ h3 ON h1.name = h3.name AND h1.level = h3.level AND h1.score Где h2.id равен NULL, а h3.id равен NULL Вы ищете уровень / балл, для которого нет более высокого уровня для этого пользователя, и нет более высокого балла, чем этот уровень.

0 голосов
/ 25 апреля 2009

Интересная проблема. Вот еще одно решение:

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;
...