在MySQL中选择除前N之外的所有内容

时间:2012-02-02 16:56:11

标签: mysql sql

我有一个数据表,我不需要保留很长时间,因此每天晚上我都要删除除最后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函数。那我现在该怎么办?

如何选择ID最高的10行以外的所有内容?

我可能只是删除所有超过一天或某事的记录,但感觉我应该能够这样做。

3 个答案:

答案 0 :(得分:2)

由于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 :(得分:1)

另一种方式:

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 

答案 2 :(得分:0)

有几种方法可以做到这一点,我更喜欢这样: -

 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:这种方法假设在截断期间没有写入,可以发出锁定以保持数据完整性