У меня есть таблица, в которой записаны оценки пользователей в игре (пользователь может отправить 5,10,20, столько же баллов, сколько он хочет). Мне нужно показать 20 лучших результатов в игре, но для каждого пользователя. (так как пользователь мог представить, например, 4 счета, которые являются вершинами в соответствии с другими оценками пользователей) Я написал:
SELECT DISTINCT
`table_highscores`.`userkey`,
max(`table_highscores`.`score`),
`table_users`.`username`,
`table_highscores`.`dateachieved`
FROM
`table_highscores`, `table_users`
WHERE
`table_highscores`.`userkey` = `table_users`.`userkey`
AND
`table_highscores`.`gamekey` = $gamekey
GROUP BY
`userkey`
ORDER BY
max(`table_highscores`.`score`) DESC,
LIMIT 0, 20;
Результат вывода в порядке, но есть проблема. Когда я вычисляю разницу дней (сегодня - это dateachieved
), результат неверен. (например, вместо того, чтобы говорить "оценка была отправлена 22 дня назад, она говорит 43 дня назад) Итак, я должен сделать второй запрос для каждого балла, чтобы найти истинную дату (что означает +20 запросов). Есть ли более короткий путь найти правильную дату?
Спасибо.
В вашем запросе вы должны использовать явный JOIN, и вам не нужно ключевое слово DISTINCT.
Этот запрос должен решить вашу проблему. Я предполагаю, что пользователь может отправлять один и тот же рекордер более одного раза в разные даты, и если это произойдет, вам нужна самая старая дата:
SELECT T1.userkey, T1.score, username, dateachieved FROM (
(SELECT userkey, max(score) AS score
FROM table_highscores
WHERE gamekey = $gamekey
GROUP BY userkey) AS T1
JOIN
(SELECT userkey, score, min(dateachieved) as dateachieved
FROM table_highscores
WHERE gamekey = $gamekey
GROUP BY userkey, score) AS T2
ON T1.userkey = T2.userkey AND T1.score = T2.score
) JOIN table_users ON T1.userkey = table_users.userkey
LIMIT 20
возникает проблема. Когда я вычисляю разницу дней (сегодня - это результат даты), результат неверен.
Есть две проблемы
dateachieved
вряд ли будет значением, связанным с высокой оценкойdateachieved
.Использование:
SELECT u.username,
hs.userkey,
hs.score,
DATEDIFF(NOW(), hs.dateachieved)
FROM TABLE_HIGHSCORES hs
JOIN TABLE_USERNAME u ON u.userkey = hs.userkey
JOIN (SELECT ths.userkey,
ths.gamekey,
ths.max_score,
MAX(ths.date_achieved) 'max_date'
FROM TABLE_HIGHSCORES ths
JOIN (SELECT t.userkey,
t.gamekey,
MAX(t.score) 'max_score'
FROM TABLE_HIGHSCORES t
GROUP BY t.userkey, t.gamekey) ms ON ms.userkey = ths.userkey
AND ms.gamekey = ths.gamekey
AND ms.max_score = ths.score
) x ON x.userkey = hs.userkey
AND x.gamekey = hs.gamekey
AND x.max_score = hs.score
AND x.max_date = hs.dateachieved
WHERE hs.gamekey = $gamekey
ORDER BY hs.score DESC
LIMIT 20
Я также изменил ваш запрос на использование синтаксиса ANSI-92 JOIN, используя синтаксис ANSI-89. Это эквивалентная производительность, но ее легче читать, синтаксис поддерживается в Oracle/SQL Server/Postgres/etc и обеспечивает согласованную поддержку LEFT JOIN.
Другое дело - вам нужно использовать backticks, когда имена таблиц и/или столбцов являются ключевыми словами MySQL.
Вы не сказали, на каком языке вы используете, чтобы рассчитать разницу, но я предполагаю, что это PHP из-за используемого там $gamekey
(который должен быть экранирован должным образом, btw).
Если ваше поле с датой указано в формате DATETIME, вы можете рассчитать разницу, подобную этому:
$diff = round((time() - strtotime($row['dateachieved'])) / 86400);
Думаю, вам нужно немного уточнить свой вопрос. Можете ли вы предоставить некоторые данные и ожидаемые результаты, а затем я буду в состоянии помочь вам?
dateachieved
(DATETIME?) И как вы рассчитываете разницу? Мне кажется, что проблема не имеет ничего общего с самим запросом.