Выберите все, кроме верхней N в MySQL - PullRequest
2 голосов
/ 02 февраля 2012

У меня есть таблица с данными, которые мне не нужно хранить очень долго, поэтому каждую ночь я хочу удалить все строки, кроме последних 20.

Для этого я нашел следующий запрос:

DELETE FROM Table WHERE ID NOT IN (
    SELECT id FROM (
        SELECT TOP 10 ID FROM Table
    ) AS x
)

MySQL не поддерживает функцию TOP, поэтому я переписал ее, чтобы использовать вместо нее LIMIT:

DELETE FROM Table WHERE ID NOT IN (
    SELECT id FROM (
        SELECT ID FROM Table ORDER BY ID DESC LIMIT 10
    ) AS x
)

К сожалению, похоже, что MySQL не поддерживает функцию LIMIT внутриподзапросы.Так что мне теперь делать?

Как выбрать все, кроме 10 строк с самым высоким идентификатором?

Я мог бы просто удалить все записи, которые старшечем день или что-то, но я чувствую, что я должен быть в состоянии сделать это таким образом.

Ответы [ 3 ]

2 голосов
/ 02 февраля 2012

Поскольку в MySQL есть ошибки при чтении из той же таблицы, что и при удалении, простейшим вариантом часто является использование временной таблицы.

INSERT INTO yourTempTable
SELECT id FROM yourTable
ORDER BY ID DESC LIMIT 10

DELETE yourTable WHERE id IN (SELECT id FROM yourTempTable)

или много ее вариантов (с использованием объединений вместо IN и т. Д.).

Основное внимание уделяется не тому, как написать второй запрос, а условиям гонки.

Ваши данные могут быть изменены другим процессом между временной таблицей и удалением.Если это возможно и имеет значение, вам нужно обернуть все это в транзакцию и установить блокировку таблицы на yourTable.

1 голос
/ 02 февраля 2012

Другой способ:

DELETE t
FROM 
    TableX AS t
  CROSS JOIN
    ( SELECT Id
      FROM TableX
      ORDER BY Id DESC
      LIMIT 1 OFFSET 9
    ) AS tenth
WHERE t.Id < tenth.id 
0 голосов
/ 02 февраля 2012

Есть несколько способов сделать это, я бы предпочел это: -

 create table tmp_table select * from your_table order by id desc limit 20;
 truncate table your_table;
 insert into your_table select * from tmp_table;
 drop table tmp_table;

На первый взгляд это кажется очень длинным,
, но лично я считаю понятным,
и очень низкимриск (плюс, это должно быть эффективно при выполнении JOIN)

PS: truncate не сбрасывает поле автоинкремента

ps2: при таком подходе предполагается, что при усечении нет записи, можно выдатьблокировка для сохранения целостности данных

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...