如何删除SQL Server 2008中的重复行?

时间:2009-10-31 19:28:48

标签: sql-server-2008

如何在SQL Server 2008中删除重复的行?

4 个答案:

答案 0 :(得分:11)

最简单的方法是使用CTE(公用表表达式)。当我要导入原始数据时,我使用这种方法;我做的第一件事就是确保它没有重复 - 我每行都有一些独特的句柄。

<强>要点:

WITH numbered AS (
    SELECT ROW_NUMBER() OVER(PARTITION BY [dupe-column-list] ORDER BY [dupe-column-list]) AS _dupe_num FROM [table-name] WHERE 1=1
)
DELETE FROM numbered WHERE _dupe_num > 1;

“dupe-column-list”部分列出了您希望值唯一的所有列。 ORDER BY是您在一组重复项中决定哪些行“获胜”并被删除的地方。 (“WHERE 1 = 1”只是个人习惯。)

它起作用的原因是因为Sql Server保留了对CTE中选择的每个源行的内部唯一引用。因此,当执行DELETE时,无论您在CTE的选择列表中放置什么,它都会知道要删除的确切行。 (如果你很紧张,你可以将“删除”更改为“SELECT *”,但由于你有重复的行,它不会有帮助;如果你可以唯一地识别每一行,你就不会读这个。)

示例:

CREATE TABLE ##_dupes (col1 int, col2 int, col3 varchar(50));
INSERT INTO ##_dupes 
    VALUES (1, 1, 'one,one')
        , (2, 2, 'two,two')
        , (3, 3, 'three,three')
        , (1, 1, 'one,one')
        , (1, 2, 'one,two')
        , (3, 3, 'three,three')
        , (1, 1, 'one,one')
        , (1, 2, '1,2');

在8行中,你有5个涉及重复问题;需要删除3行。你可以看到这个问题:

SELECT col1
    , col2
    , col3
    , COUNT(1) AS _total 
    FROM ##_dupes 
    WHERE 1=1 
    GROUP BY col1, col2, col3
    HAVING COUNT(1) > 1
    ORDER BY _total DESC;

现在运行以下查询以删除重复项,从每组重复项中留下1行。

WITH numbered AS (
    SELECT ROW_NUMBER() OVER(PARTITION BY col1, col2, col3 ORDER BY col1, col2, col3) AS _dupe_num FROM ##_dupes WHERE 1=1
)
DELETE FROM numbered WHERE _dupe_num > 1;

现在你剩下5行,其中没有一行是重复的。

答案 1 :(得分:4)

添加主键。说真的,每张桌子应该有一张。它可以是一个标识,您可以忽略它,但要确保每个表都定义了一个主键。

想象一下,你有一个像这样的表:

create table T (
    id int identity,
    colA varchar(30) not null,
    colB varchar(30) not null
)

然后你可以这样说:

delete T
from T t1
where exists
(select null from T t2
where t2.colA = t1.colA
and t2.colB = t1.colB
and t2.id <> t1.id)

另一个技巧是选择具有最小id的不同记录,并保留:

delete T
where id not in
(select min(id) from T
group by colA, colB)

(对不起,我还没有测试过这些,但其中一个想法可能会引导您找到解决方案。)

请注意,如果您没有主键,唯一的另一种方法是利用像ROWID这样的伪列 - 但我不确定SQL Server 2008是否提供了这个想法

答案 2 :(得分:3)

即使您没有主键,您也可以通过以下代码删除重复数据

delete from (Tablename)
          where tablename.%%physloc%%
          NOT IN (select MIN(b.%%physloc%%)
          from tablename b
          group by b.Column1,b.column2,b.column3
          );

答案 3 :(得分:0)

假设您有一个名为id的主键,其他列是col2 ... coln,而“重复”行则表示除PK之外的所有列值都重复的所有行

delete from A where id not in
(select min(id) from A
group by col2, col3, ...coln) as x

即。所有非PK列上的小组