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

578

如何删除没有唯一行ID的重复行?

我的表格是:

col1  col2 col3 col4 col5 col6 col7
john  1    1    1    1    1    1 
john  1    1    1    1    1    1
sally 2    2    2    2    2    2
sally 2    2    2    2    2    2

在去除重复项后,我希望保留以下内容:

john  1    1    1    1    1    1
sally 2    2    2    2    2    2
我尝试了一些查询,但我认为它们依赖于拥有行ID,因此我没有得到期望的结果。例如:
DELETE
FROM table
WHERE col1 IN (
    SELECT id
    FROM table
    GROUP BY id
    HAVING (COUNT(col1) > 1)
)

9
这不是第一个链接的重复。在这个问题中没有行ID,而在链接的问题中有行ID。非常不同。 - Alien Technology
将以下程序相关内容从英语翻译成中文。仅返回翻译后的文本:更改“SELECT id FROM table GROUP BY id HAVING”以具有聚合函数,例如MAX/MIN,并使其工作。 - messed-up
29个回答

1
如果您有临时添加表格列的能力,这是我的解决方案:
ALTER TABLE dbo.DUPPEDTABLE ADD RowID INT NOT NULL IDENTITY(1,1)

然后使用MIN和GROUP BY的组合执行DELETE操作

DELETE b
FROM dbo.DUPPEDTABLE b
WHERE b.RowID NOT IN (
                     SELECT MIN(RowID) AS RowID
                     FROM dbo.DUPPEDTABLE a WITH (NOLOCK)
                     GROUP BY a.ITEM_NUMBER,
                              a.CHARACTERISTIC,
                              a.INTVALUE,
                              a.FLOATVALUE,
                              a.STRINGVALUE
                 );

验证 DELETE 操作是否正确执行:

SELECT a.ITEM_NUMBER,
    a.CHARACTERISTIC,
    a.INTVALUE,
    a.FLOATVALUE,
    a.STRINGVALUE, COUNT(*)--MIN(RowID) AS RowID
FROM dbo.DUPPEDTABLE a WITH (NOLOCK)
GROUP BY a.ITEM_NUMBER,
    a.CHARACTERISTIC,
    a.INTVALUE,
    a.FLOATVALUE,
    a.STRINGVALUE
ORDER BY COUNT(*) DESC 

结果中不应该有计数大于1的行。最后,删除rowid列:
ALTER TABLE dbo.DUPPEDTABLE DROP COLUMN RowID;

1
哇,看了这些答案后我感到非常愚蠢,它们像是专家的答案,包含所有CTE、临时表等等。 而我所做的只是简单地通过使用MAX聚合了ID列就使其正常工作了。
DELETE FROM table WHERE col1 IN (
    SELECT MAX(id) FROM table GROUP BY id HAVING ( COUNT(col1) > 1 )
)

注意:您可能需要多次运行它以删除重复项,因为这只会一次删除一组重复行。


这样做不行,因为它会删除所有重复项而不保留原始记录。OP要求保留原始记录。 - 0xdd
4
不正确,MAX函数会返回满足条件的最大ID。如果您不同意,请提出论据以供反对。 - messed-up

1

参考https://support.microsoft.com/zh-cn/help/139444/how-to-remove-duplicate-rows-from-a-table-in-sql-server

去重的想法涉及以下内容:

  • a) 保护那些不是重复的行
  • b) 保留符合重复条件的多个行中的一个。

步骤如下:

  • 1) 首先确定满足重复定义的行并将它们插入到临时表中,比如说 #tableAll。
  • 2) 将非重复(单行)或不同的行插入到临时表中,比如说 #tableUnique。
  • 3) 通过连接#tableAll从源表中删除重复项。
  • 4) 将#tableUnique中的所有行插入到源表中。
  • 5) 删除#tableAll和#tableUnique。

0
DELETE p1 FROM Person p1,
    Person p2
WHERE
    p1.Email = p2.Email AND p1.Id > p2.Id

0

另一种在一步中删除重复行而不丢失信息的方法如下:

delete from dublicated_table t1 (nolock)
join (
    select t2.dublicated_field
    , min(len(t2.field_kept)) as min_field_kept
    from dublicated_table t2 (nolock)
    group by t2.dublicated_field having COUNT(*)>1
) t3 
on t1.dublicated_field=t3.dublicated_field 
    and len(t1.field_kept)=t3.min_field_kept

0
DELETE FROM TBL1  WHERE ID  IN
(SELECT ID FROM TBL1  a WHERE ID!=
(select MAX(ID) from TBL1  where DUPVAL=a.DUPVAL 
group by DUPVAL
having count(DUPVAL)>1))

0
DECLARE @TB TABLE(NAME VARCHAR(100));
INSERT INTO @TB VALUES ('Red'),('Red'),('Green'),('Blue'),('White'),('White')
--**Delete by Rank**
;WITH CTE AS(SELECT NAME,DENSE_RANK() OVER (PARTITION BY NAME ORDER BY NEWID()) ID FROM @TB)
DELETE FROM CTE WHERE ID>1
SELECT NAME FROM @TB;
--**Delete by Row Number** 
;WITH CTE AS(SELECT NAME,ROW_NUMBER() OVER (PARTITION BY NAME ORDER BY NAME) ID FROM @TB)
DELETE FROM CTE WHERE ID>1;
SELECT NAME FROM @TB;

从一个包含数百万条记录的大表中删除重复项可能需要很长时间。我建议您将所选行批量插入到临时表中,而不是直接删除。 '--重写您的代码(注意第3行) WITH CTE AS(SELECT NAME,ROW_NUMBER() OVER (PARTITION BY NAME ORDER BY NAME) ID FROM @TB) SELECT * INTO #unique_records FROM CTE WHERE ID =1;' - Emmanuel Bull

0

0
新替换的表将只包含不重复的记录,
案例:当您没有外键并且数据在所有列中都是重复的情况下。
create or replace table table_x  as select distinct * from table_x;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接