T-SQL:删除所有重复的行但保留一个[重复]
Posted
技术标签:
【中文标题】T-SQL:删除所有重复的行但保留一个[重复]【英文标题】:T-SQL: Deleting all duplicate rows but keeping one [duplicate] 【发布时间】:2011-08-26 21:23:00 【问题描述】:我有一个包含大量行的表。不允许重复,但由于行的创建方式存在问题,我知道此表中有一些重复项。 我需要从键列的角度消除多余的行。其他一些列可能有略有不同的数据,但我不在乎。但是,我仍然需要保留其中的一行。 SELECT DISTINCT 不起作用,因为它对所有列进行操作,我需要根据键列抑制重复项。
我怎样才能删除多余的行但仍然有效地保留一个?
【问题讨论】:
嘿,“删除所有重复的行,但保留一个 [duplicate]”。 【参考方案1】:您没有说您使用的是什么版本,但在 SQL 2005 及更高版本中,您可以使用带有OVER Clause 的公用表表达式。它有点像这样:
WITH cte AS (
SELECT[foo], [bar],
row_number() OVER(PARTITION BY foo, bar ORDER BY baz) AS [rn]
FROM TABLE
)
DELETE cte WHERE [rn] > 1
试一试,看看你会得到什么。
(编辑:为了提供帮助,有人编辑了 CTE 中的 ORDER BY
子句。需要说明的是,您可以在此处按您想要的任何内容进行排序,它不必是 cte 返回的列之一. 事实上,这里的一个常见用例是“foo, bar”是组标识符,“baz”是某种时间戳。为了保持最新,你会做ORDER BY baz desc
)
【讨论】:
这会保留最后一个重复行还是第一行? 刚刚回到这个答案并注意到这个问题:它将保留哪个骗子。如所写,它将保留“第一个”重复行,其中“第一个”表示“根据 baz 的最低排序”。当然,如果您不确定将删除/保留什么,请将删除转换为选择并确保。安全总比后悔好。 如果它是批量执行的,不要忘记 WITH 之前的分号。交易msdn.microsoft.com/en-us/library/ms175972.aspx @SumGuy:不;行号就足够了。但我喜欢先将其作为选择来运行,以检查将受到影响的内容。此外,我刚刚进行了快速测试,似乎 SQL Server 足够聪明,不会将不需要的列向前传送。我通过查看实际执行计划中的输出列列表来确定这一点,对于我选择所有内容加上行号和仅行号的情况;两者是相同的。 行数较多时,可能不推荐使用 DELETE(FULL 恢复也会导致事务日志填满)。最好执行 SELECT * INTO NewTable FROM cte 然后删除旧表。对于非常大的表,这会更快。【参考方案2】:查询示例:
DELETE FROM Table
WHERE ID NOT IN
(
SELECT MIN(ID)
FROM Table
GROUP BY Field1, Field2, Field3, ...
)
这里fields
是您要将重复行分组的列。
【讨论】:
使用这种格式我得到了以下错误,有什么想法吗? "ERROR 1093 (HY000): 您不能在 FROM 子句中指定目标表 'Table' 进行更新" @M1ke mysql 不允许更新从子查询引用的主表,但有一个解决方法;将“FROM Table”更改为“FROM (SELECT * FROM Table) AS t1”,这会将表存储在临时表中,以便更新主表。 谢谢,我实际上在其他地方找到了相同的答案,但不记得在哪里 - 所以加 1! 很好。但是如果我们没有主键呢? @merdan,它适用于任何可排序的东西。例如以下是有效的select min(id) from ( select newid() as id union select newid() as id ) as a
【参考方案3】:
这是我的转折点,带有一个可运行的示例。 注意这仅适用于Id
唯一且您在其他列中有重复值的情况。
DECLARE @SampleData AS TABLE (Id int, Duplicate varchar(20))
INSERT INTO @SampleData
SELECT 1, 'ABC' UNION ALL
SELECT 2, 'ABC' UNION ALL
SELECT 3, 'LMN' UNION ALL
SELECT 4, 'XYZ' UNION ALL
SELECT 5, 'XYZ'
DELETE FROM @SampleData WHERE Id IN (
SELECT Id FROM (
SELECT
Id
,ROW_NUMBER() OVER (PARTITION BY [Duplicate] ORDER BY Id) AS [ItemNumber]
-- Change the partition columns to include the ones that make the row distinct
FROM
@SampleData
) a WHERE ItemNumber > 1 -- Keep only the first unique item
)
SELECT * FROM @SampleData
结果:
Id Duplicate
----------- ---------
1 ABC
3 LMN
4 XYZ
不知道为什么这是我首先想到的......绝对不是最简单的方法,但它有效。
【讨论】:
这不会保留一份原件的副本。这也会删除原始文件。 嗨@Sandy,你验证了吗?我在四年前回答过,我不记得我是否在真实数据上测试过。 是的,我检查了真实数据。这也会删除原始文件。 能否请我们删除这篇文章,因为除非您测试并阅读 cmets,否则我很危险! @Fandango68:我相信我已经解释了帖子正文中的风险。复制和粘贴随机 Internet 代码 sn-ps 是一项危险的工作。非常欢迎您投票删除帖子,看看社区是否同意。以上是关于T-SQL:删除所有重复的行但保留一个[重复]的主要内容,如果未能解决你的问题,请参考以下文章