Есть ли альтернатива IN с LIMIT?

#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» должен быть проиндексирован в таблице «Рекордов»