删除重复的行 - 无法找到决定性的答案

时间:2011-01-05 17:56:31

标签: sql sql-server sql-server-2005 tsql sql-server-2008

你马上想我直接到这里问我的问题,但我搜索了很多东西,没有找到决定性的答案。

事实:我有一张包含330万行,20列的表格。 第一行是主键,因此是唯一的。

我必须删除列2到列11重复的所有行。实际上是一个基本问题,但是有很多不同的方法,而每个人最终都会寻求相同的解决方案,删除重复的内容。

我个人在考虑GROUP BY HAVING COUNT(*)> 1 这是要走的路还是你的建议?

提前多多感谢! →

4 个答案:

答案 0 :(得分:5)

作为一般答案:

WITH cte AS (
  SELECT ROW_NUMBER() OVER (
      PARTITION BY <groupbyfield> ORDER BY <tiebreaker>) as rn
  FROM Table)
DELETE FROM cte
WHERE rn > 1;

我觉得这比GROUP BY更强大,更灵活...... HAVING。事实上,GROUP BY ... HAVING只给你重复,你仍然留下了在重复中选择“守护者”的“琐碎”任务。

ROW_NUMBER OVER(...)可以更好地控制如何区分重复项(决胜局)并允许“保留前三个重复项”之类的行为,而不仅仅是“保持1”,这实际上是一种行为很难处理GROUP BY ... HAVING。

问题的另一部分是如何处理3.3M行。好吧,3.3M不是 大,但我仍然建议分批进行。一次删除TOP 10000,否则您将把一个巨大的事务推送到日志中,并可能压倒您的日志驱动器。

最后一个问题是这是否会令人满意。这取决于您的架构。如果ROW_NUMBER()必须扫描整个表和假脱机计数,并且您必须批量重复N次,那么它将无法执行。适当的索引会有所帮助。但我不能再说了,不知道所涉及的确切模式(聚簇索引/堆的结构,所有非聚集索引等)。

答案 1 :(得分:2)

按您想要唯一的字段分组,并为您的pk字段获取汇总值(如min)。然后将这些结果插入到新表中。

答案 2 :(得分:2)

如果你有SQL Server 2005或更新版本,那么最简单的方法是使用CTE(公用表表达式)。

您需要知道要对数据进行“分区”的标准 - 例如创建被认为相同/重复的数据分区 - 然后您需要通过某些内容对这些分区进行排序 - 例如序列号,日期/时间等。

您没有提供有关表格的更多详细信息 - 所以,让我给您一个示例:

;WITH Duplicates AS
(
   SELECT  
       OrderID,
       ROW_NUMBER() OVER (PARTITION BY CustomerID ORDER BY OrderDate DESC) AS RowN
   FROM
       dbo.Orders
)
DELETE FROM dbo.Orders
WHERE RowN > 1

CTE(WITH ... AS :...)为下一个SQL语句提供了一个“内联视图” - 它不是持久的或任何东西 - 它只适用于下一个语句然后它就消失了。

基本上,我是按CustomerID“分组”(分区)我的订单,并按OrderDate排序。因此,对于每个CustomerID,我得到一个新的“数据组”,其中的行号从1开始。ORDER BY OrderDate DESC为每个客户提供RowN = 1值的最新订单 - 这是一个订单我保留。

根据CTE(WITH.....表达式)删除每个客户的所有其他订单。

显然,您需要根据自己的情况对其进行调整 - 但使用PARTITION BYROW_NUMBER()的CTE是一种非常可靠且易于删除重复项的技术。

答案 3 :(得分:1)

如果您不想处理新表删除,请使用DELETE TOP(1)。使用子查询获取所有重复行的ID,然后使用delete top删除有多行的位置。如果有多个副本,您可能必须运行多次,但是您明白了。

DELETE TOP(1) FROM Table
WHERE ID IN (SELECT ID FROM Table GROUP BY Field HAVING COUNT(*) > 1)

希望你能得到这个想法。这只是一些伪代码来帮助演示。