【发布时间】:2010-09-07 23:09:31
【问题描述】:
在 sql 中从表中删除所有行但在顶部保留 n 行的最佳方法是什么?
【问题讨论】:
标签: sql
在 sql 中从表中删除所有行但在顶部保留 n 行的最佳方法是什么?
【问题讨论】:
标签: sql
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 创建临时表来解决子查询性能问题.
我会选择要保留到临时表或表变量中的行集的 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 的命名可能是因为它会被删除。
不使用 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 子查询'
我猜还没有。
【讨论】:
我认为使用虚拟表会比 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
【讨论】:
这就是我的做法。这种方法更快更简单:
使用 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 - 适合您的情况。
【讨论】:
我不知道其他风格,但 MySQL DELETE 允许 LIMIT。
如果您可以订购东西以使您想要保留的 n 行位于底部,那么您可以执行 DELETE FROM table LIMIT tablecount-n。
编辑
哎呀。我想我更喜欢Cory Foy's 的回答,假设它适用于您的情况。相比之下,我的方式有点笨拙。
【讨论】:
这确实是特定于语言的,但我可能会为 SQL 服务器使用类似以下的内容。
declare @n int
SET @n = SELECT Count(*) FROM dTABLE;
DELETE TOP (@n - 10 ) FROM dTable
如果您不关心确切的行数,总有
DELETE TOP 90 PERCENT FROM dTABLE;
【讨论】:
我会使用下面的技术来解决它。该示例需要一个 article 表,每行都有一个 id。
Delete article where id not in (select top 1000 id from article)
编辑:回答我自己的问题太慢了...
【讨论】:
重构?
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
编辑:在查询分析器中都试过了,当前答案是禁食的(该死的顺序...)
【讨论】:
更好的方法是将您想要的行插入另一个表,删除原始表,然后重命名新表,使其与旧表具有相同的名称
【讨论】:
我有一个技巧可以避免对每一行执行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很重要,以确保查询到正确的结果。
【讨论】: