我需要有效地获取所有重复条目的整行

时间:2015-06-23 17:27:19

标签: sql-server database performance count duplicates

互联网!我对SQL很陌生,我需要在某些字段中获取包含重复信息的所有行,并将它们显示在其他重复项旁边(按重复项分组)。

例如,假设我有一个包含列的表:

A,B,C,D,E,F,G

我希望能够获得所有条目(完整行),其中B,C,D和E与另一个条目共享相同的值,并在原始条目旁边显示重复项。 我已经有了一个解决方案,但效率非常低。我正在努力改善我的运行时间

我原来的解决方案是:

    SELECT TOP 1000 
    A,
    B,
    C,
    D,
    E,
    F,
    G
    FROM tbl_myTable
    WHERE (B+C+D+E+F+G) IN (
        SELECT                                  
            B+C+D+E+F+G                 
        FROM                                    
            tbl_myTable                             
        GROUP BY                                    
            B,C,D,E,F,G                 
        HAVING COUNT(*) > 1 
    )

    ORDER BY B,C,D,E,F,G ASC

这给了我想要的结果,但它非常缓慢(花了15分钟才能运行)。我使用临时表重写了我的解决方案,并使用此脚本将时间缩短到5分钟的运行时间:

    --Drop the temp table if it exists.
IF OBJECT_ID('tempdb..#Temp1') IS NOT NULL
DROP TABLE #Temp1

SELECT                              
     B+C+D+E+F+G AS CompareString       
 INTO #Temp1
 FROM tbl_myTable                           
 GROUP BY                                   
 B,C,D,E,F,G                
 HAVING COUNT(*) > 1

 SELECT TOP 1000 
 A,
 B,
 C,
 D,
 E,
 F,
 G
 FROM tbl_myTable
 WHERE (B+C+D+E+F+G) IN (
     SELECT * FROM #Temp1
 )
 ORDER BY B,C,D,E,F,G ASC

五分钟似乎还很长一段时间。有更快的方法吗?我是SQL的新手,所以如果我做的事情不好,请告诉我!谢谢!

2 个答案:

答案 0 :(得分:0)

如果没有实际数据,我必须在这里做一些假设。

首先,我假设您的字母字段都是文本类型,并且您使用+来连接而不是添加数值(否则当A = 1 B = 2且C = 3时A + B + C = 6当A = 2 B = 3且C = 1时,这将不匹配)。

接下来我将假设在每一行中都有某种关键字段未在您的示例中显示。像tbl_myTable.MyTableKey bigint IDENTITY(1,1)NOT NULL。

假设这一切,我试试......

SELECT
    [BaseTable].MyTableKey AS [Original Record],
    [DupCheckTable].MyTableKey AS [Duplicate Record]
FROM
    tbl_myTable [BaseTable]
    LEFT OUTER JOIN tbl_myTable [DupCheckTable] ON 
            [BaseTable].A = [DupCheckTable].A
            AND
            [BaseTable].B = [DupCheckTable].B
            AND
            --... repeat for each actual field
            --AND
            [BaseTable].G = [DupCheckTable].G
            AND
            [BaseTable].MyTableKey  < [DupCheckTable].MyTableKey  --the less than operator prevents you from getting each match twice
WHERE
    [DupCheckTable].MyTableKey IS NOT NULL

我认为这会更快地运行,因为您可以使用表键(可能是索引)作为连接的一部分。此外,您将任何(或我的)查询提供给Tuning Advisor,以查看它认为对统计数据和索引有帮助的内容。

答案 1 :(得分:0)

我会做这样的事情:

with cte as (
   SELECT *
      , count(*) over (partition by B, C, D, E, F, G) as cnt
      , dense_rank() over (order by B, C, D, E, F, G) as grp
   FROM STI.[dbo].[tbl_Consignee]
)
select * 
from cte
where cnt > 1
order by grp

基本上,dense_rank()调用为每个唯一元组提供一个标识符(因此您可以使用order by子句将重复项放在彼此旁边),并且计数会计算每个组的行数。