#mysql
#mysql
Вопрос:
Я хочу реализовать процедуру, которая обновляет «высокий балл» или «лучшие 10 баллов» в игре.
Моя идея состоит в том, чтобы выполнить следующий код:
DELETE FROM Highscore
WHERE scoreId NOT IN
(SELECT scoreId FROM Highscore ORDER BY value DESC LIMIT 10)
Но затем я получаю сообщение об ошибке, что версия MySQL, которую я использую, не поддерживается IN
LIMIT
.
Есть ли другой способ?
Ответ №1:
DELETE FROM Highscore ORDER BY value DESC LIMIT 10,5
Это последнее 5
может быть любым числом. Если вы запускаете это каждый раз, когда добавляется оценка, вы можете использовать ее как 1
. Чтобы обеспечить большую погрешность, используйте 10
.
РЕДАКТИРОВАТЬ: Извините, по-видимому, вы не можете использовать здесь смещение. В таком случае:
DELETE FROM Highscore WHERE value < (SELECT value FROM Highscore ORDER BY value DESC LIMIT 10,1)
Если это не позволяет вам этого сделать (выберите из той же таблицы, что и обновление / удаление), попробуйте:
SET @tmp = (SELECT value FROM Highscore ORDER BY value DESC LIMIT 10,1)
DELETE FROM Highscore WHERE value < @tmp
ОТРЕДАКТИРУЙТЕ еще раз: как указано в комментарии, вызывает проблемы, если 11-е значение равно 10-му. Попробуй:
SET @id = (SELECT scoreId FROM Highscore ORDER BY value DESC, scoreId DESC LIMIT 10,1), @val = (SELECT value FROM Highscore ORDER BY value DESC LIMIT 10,1)
DELETE FROM Highscore WHERE value <= @val AND scoreId < @id
Упорядочение по scoreId в первой переменной гарантирует, что при наличии нескольких с одинаковым счетом там останется не менее 10.
Комментарии:
1.
SET @tmp = (SELECT value FROM Highscore ORDER BY value DESC LIMIT 10,1) DELETE FROM Highscore WHERE value < @tmp
да, это работает, но немного глючит (если строка 11 имеет то же значение, что и строка 10)
Ответ №2:
Другой обходной путь для:
DELETE FROM Highscore
WHERE scoreId NOT IN
(SELECT scoreId FROM Highscore ORDER BY value DESC LIMIT 10)
заключается в том, чтобы вложить подзапрос LIMIT
внутрь другого подзапроса:
DELETE FROM Highscore
WHERE scoreId NOT IN
(SELECT scoreId FROM
(SELECT scoreId FROM Highscore ORDER BY value DESC LIMIT 10)
AS tmp
)
Но я думаю, что лучше не объединять вложенные подзапросы со ссылками в WHERE
предложении на ту же таблицу, из которой вы хотите удалить. Я думаю, что лучше использовать JOIN
:
DELETE h
FROM
Highscore AS h
CROSS JOIN
( SELECT scoreId FROM Highscore ORDER BY value DESC LIMIT 10
) AS tmp
WHERE h.scoreId NOT IN (SELECT scoreId FROM tmp)
или даже лучше, если вы можете сделать это проще (и, возможно, быстрее с включенным индексом value
), как это возможно в вашем случае (обратите внимание, что следующее будет содержать более 10 строк, если на 10-м месте есть связи):
DELETE h
FROM
Highscore AS h
CROSS JOIN
( SELECT value
FROM Highscore
ORDER BY value DESC
LIMIT 1 OFFSET 9
) AS tmp
WHERE h.value < tmp.value
Ответ №3:
Вместо вставки новых строк вы могли бы обновить существующие строки, используя UPDATE
.
Другим способом было бы отредактировать выборку, которая получает рекорд. Таким образом, вы также отслеживаете все предыдущие рекорды. Использование ORDER BY
и LIMIT
позволит вам выполнить такой запрос.
Комментарии:
1. вы уверены, что хотели ответить на этот вопрос?
2. ОБНОВЛЕНИЕ? мн? строка с наименьшим количеством баллов? Я не думаю, что это хорошая идея. Если игра заканчивается, количество очков всех игроков отправляется в базу данных (количество людей является переменным). Так что я не знаю, как использовать UPDATE в этом случае
3. Вы можете использовать
LIMIT
сDELETE
, но неOFFSET
4. @ypercube Я не упомянул СМЕЩЕНИЕ в своем ответе?
5. @Marcus:
LIMIT x,y
это то жеLIMIT y OFFSET x
самое, что и .
Ответ №4:
У меня нет установки MySQL для тестирования этого, но в TSQL вы могли бы сделать что-то вроде
delete from HighSchore
where scoreID not in
(select top 10 scoreID from HighScore order by Value desc)
Конечно, лучше сделать это с помощью внешнего соединения вместо подзапроса.
Кроме того, на мой взгляд, вы никогда не должны удалять подобные данные, а просто извлекать топ-10 всякий раз, когда вам нужно.
select top 10 value
from Highscore
order by Value desc;
Комментарии:
1. mysql не допускает top / limit во внутренних запросах.
2. @ItayMoav серьезно? Тогда я оставлю это здесь на случай, если кому-нибудь это понадобится для других серверов.
3. Мы ВСЕ (пользователи mysql) надеемся, что это скоро будет исправлено, но, к сожалению, это так (может быть, в последних версиях, которые в настоящее время начинают выходить, это существует, но не уверен, что они пока стабильны).
4.
LIMIT
не допускается в подзапросах:INALLANYSOME (subquery with LIMIT)
. Это разрешено в других подзапросах.
Ответ №5:
попробуйте это.
Сначала создайте временную таблицу из 10 лучших
CREATE TEMPORARY TABLE tmp_highscores
(SELECT scoreId FROM Highscore ORDER BY value DESC LIMIT 10);
Затем удалите те, которые НЕ ВХОДЯТ В топ-10
DELETE FROM Highscore WHERE scoreId NOT IN
(SELECT scoreId FROM tmp_highscores)
И не забывайте: «scoreId» должен быть проиндексирован в таблице «Рекордов»