删除重复分组数据的最佳方法 - SQL Server 2008

时间:2013-06-28 05:42:50

标签: sql sql-server sql-server-2008 relational-database

我有两张桌子 - >订单和OrderLine。订单包含标题信息,是一对多关系的一面。 OrderLine包含组成订单的行,是多方。

假设我有3个订单,每个订单都有自己的ID,但每个订单的订单行数据相同,我认为这是重复,但只有当组中的所有记录都相同时才会发生。

我尝试过使用CheckSum_Agg,但是会产生大量误报,导致删除的记录不完全重复。

试图避免使用令人讨厌,费力的嵌套游标。

有什么想法吗?

发布编辑: - CheckSum_Agg ...

返回的误报示例
Create Table #OrderLine(OrderId Int,ProductTypeId Int,ProductId Int);
Insert Into #OrderLine(OrderId,ProductTypeId,ProductId)
Values(1,1,5),(1,2,6),(2,1,6),(2,2,5)

Select CHECKSUM_Agg(ProductTypeId),CHECKSUM_Agg(ProductId)
From #OrderLine
Group By OrderId

Drop Table #OrderLine

2 个答案:

答案 0 :(得分:1)

我认为CheckSum_Agg是一个好的开始。你可能只在一列上做CheckSum_Agg。如果您为每个感兴趣的列执行一个CheckSum_Agg,您将能够找到所有重复项。您可能对应用CheckSum_Agg不感兴趣的唯一列是OrderLine.id和OrderLine.OrderId。

如果两个订单相同,这是一个逐行检查的查询:

with o as (
  select distinct orderid from orderline)
, ol as (select * from orderline)
select o1.orderid as o1, o2.orderid as o2
from o o1, o o2 
where o1.orderid <> o2.orderid and
0= (select count(*) 
          from (select * from ol where ol.orderid = o1.orderid) ol1 
          full outer join 
            (select * from ol where ol.orderid = o2.orderid) ol2 
            on ol1.producttypeid = ol2.producttypeid
            and ol1.productid = ol2.productid
          where (ol2.orderid is null or ol1.orderid is null))

这是一个小提琴,展示了它的实际效果:http://sqlfiddle.com/#!3/359e5/8

这里的想法是获得订单的所有对(o1,o2)并将o1的订单线ol1与o2的订单线ol2相匹配,以查看它们是否匹配。如果它们都匹配,那么它们就是彼此的重复。

这可能是一项非常昂贵的操作。我建议一个索引,它包含完整外连接critera中的所有列,以加快速度。

答案 1 :(得分:0)

如果您允许在桌子上使用傻瓜,我建议您创建一个代理键,以便轻松移除。最好不要首先允许它们,具有独特的约束。但试着这个清理。

Create Table #OrderLine(Pk INT IDENTITY PRIMARY KEY, OrderId Int,ProductTypeId Int,ProductId Int);
Insert Into #OrderLine(OrderId,ProductTypeId,ProductId)
Values(1,1,5),(1,2,6),(2,1,6),(2,2,5),(1,1,5), (1,1,5)

--check
SELECT * FROM #OrderLine

--any dupes?
SELECT * FROM #OrderLine WHERE Pk NOT IN (
    Select Min(Pk)
    From #OrderLine
    Group By OrderId,ProductTypeId,ProductId
)

--delete the dupes
DELETE FROM #OrderLine WHERE Pk NOT IN (
    Select Min(Pk)
    From #OrderLine
    Group By OrderId,ProductTypeId,ProductId
)

--check
SELECT * FROM #OrderLine

Drop Table #OrderLine