【问题标题】:Delete all but top n from database table in SQL从SQL中的数据库表中删除除top n之外的所有内容
【发布时间】:2010-09-07 23:09:31
【问题描述】:

在 sql 中从表中删除所有行但在顶部保留 n 行的最佳方法是什么?

【问题讨论】:

    标签: sql


    【解决方案1】:
    DELETE FROM Table WHERE ID NOT IN (SELECT TOP 10 ID FROM Table)
    

    编辑:

    Chris 带来了良好的性能表现,因为将为每一行运行 TOP 10 查询。如果这是一次性的事情,那么它可能没什么大不了的,但如果这是一件普通的事情,那么我确实仔细研究了它。

    【讨论】:

    • 请注意,您可以通过手动创建临时表(假设这是一个不常见的操作)或将查询编写为DELETE FROM Table WHERE ID NOT IN (SELECT id FROM (SELECT TOP 10 ID FROM Table) AS x) 来强制 MySQL 创建临时表来解决子查询性能问题.
    • 谢谢。那是救生员:)
    • 子查询多次运行,是真的吗? stackoverflow.com/questions/18790796/…
    • @ Daniel Schaffer 听起来他们没有任何数据库或业务逻辑问题。听起来像是一个完全正常的保留政策。
    • 如果我的表中没有主键怎么办?
    【解决方案2】:

    我会选择要保留到临时表或表变量中的行集的 ID 列。然后删除临时表中不存在的所有行。其他用户提到的语法:

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

    有一个潜在的问题。将对表中的每一行执行“SELECT TOP 10”查询,这可能会对性能造成巨大影响。您希望避免一遍又一遍地进行相同的查询。

    根据您作为原始 SQL 语句列出的内容,此语法应该有效:

    create table #nuke(NukeID int)
    
    insert into #nuke(Nuke) select top 1000 id from article
    
    delete article where not exists (select 1 from nuke where Nukeid = id)
    
    drop table #nuke
    

    【讨论】:

    • insert into #nuke(Nuke) ... 应该是:insert into #nuke(NukeID) ... 此外,nuke 的名称令人困惑,因为您试图不删除这些行。 nuke 的命名可能是因为它会被删除。
    【解决方案3】:

    不使用 MS SQL 的用户的未来参考。

    在 PostgreSQL 中使用 ORDER BY 和 LIMIT 而不是 TOP。

    DELETE FROM table
    WHERE id NOT IN (SELECT id FROM table ORDER BY id LIMIT n);
    

    MySQL——嗯……

    错误 -- 这个版本的 MySQL 还不支持 'LIMIT & IN/ALL/ANY/SOME 子查询'

    我猜还没有。

    【讨论】:

      【解决方案4】:

      我认为使用虚拟表会比 IN 子句或临时表好得多。

      DELETE 
          Product
      FROM
          Product
          LEFT OUTER JOIN
          (
              SELECT TOP 10
                  Product.id
              FROM
                  Product
          ) TopProducts ON Product.id = TopProducts.id
      WHERE
          TopProducts.id IS NULL
      

      【讨论】:

        【解决方案5】:

        这就是我的做法。这种方法更快更简单:

        使用 OFFSET 命令从 MS SQL 中的数据库表中删除除 top n 之外的所有内容

        WITH CTE AS
            (
            SELECT  ID
            FROM    dbo.TableName
            ORDER BY ID DESC
            OFFSET 11 ROWS
            )
        DELETE CTE;
        

        将ID 替换为您要排序的列。 将OFFSET 之后的数字替换为您要保留的行数。 选择 DESC 或 ASC - 适合您的情况。

        【讨论】:

        • 在这种情况下,offset 不是您想要保留的行数吗?
        • @NapkinBob 是的。
        【解决方案6】:

        我不知道其他风格,但 MySQL DELETE 允许 LIMIT。

        如果您可以订购东西以使您想要保留的 n 行位于底部,那么您可以执行 DELETE FROM table LIMIT tablecount-n。

        编辑

        哎呀。我想我更喜欢Cory Foy's 的回答,假设它适用于您的情况。相比之下,我的方式有点笨拙。

        【讨论】:

          【解决方案7】:

          这确实是特定于语言的,但我可能会为 SQL 服务器使用类似以下的内容。

          declare @n int
          SET @n = SELECT Count(*) FROM dTABLE;
          DELETE TOP (@n - 10 ) FROM dTable
          

          如果您不关心确切的行数,总有

          DELETE TOP 90 PERCENT FROM dTABLE;
          

          【讨论】:

          • 这些都不起作用。该问题询问如何仅保留表中的前 N ​​行。这两个示例都只保留底部的 N 行。
          • 在 MSSQL 中运行良好。只需添加排序即可删除底部而不是顶部?
          【解决方案8】:

          我会使用下面的技术来解决它。该示例需要一个 article 表,每行都有一个 id。

          Delete article where id not in (select top 1000 id from article)
          

          编辑:回答我自己的问题太慢了...

          【讨论】:

            【解决方案9】:

            重构?

            Delete a From Table a Inner Join (
                Select Top (Select Count(tableID) From Table) - 10) 
                    From Table Order By tableID Desc
            ) b On b.tableID = A.tableID
            

            编辑:在查询分析器中都试过了,当前答案是禁食的(该死的顺序...)

            【讨论】:

              【解决方案10】:

              更好的方法是将您想要的行插入另一个表,删除原始表,然后重命名新表,使其与旧表具有相同的名称

              【讨论】:

              • 为什么这样更好?快点?需要几个额外的命令才能完成。
              【解决方案11】:

              我有一个技巧可以避免对每一行执行TOP 表达式。我们可以将TOP 与MAX 结合起来得到我们想要保留的MaxId。然后我们只删除大于MaxId 的所有内容。

              -- Declare Variable to hold the highest id we want to keep. 
              DECLARE @MaxId as int = (
              SELECT MAX(temp.ID)
              FROM (SELECT TOP 10 ID FROM table ORDER BY ID ASC) temp
              )
              
              -- Delete anything greater than MaxId. If MaxId is null, there is nothing to delete.
              IF @MaxId IS NOT NULL
                  DELETE FROM table WHERE ID > @MaxId
              

              注意:声明MaxId时使用ORDER BY很重要,以确保查询到正确的结果。

              【讨论】:

                猜你喜欢
                • 2015-10-15
                • 1970-01-01
                • 2020-09-01
                • 2010-10-09
                • 2012-04-10
                • 2010-11-26
                • 1970-01-01
                • 2018-01-15
                • 1970-01-01
                相关资源
                最近更新 更多