如何在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个回答

6

尝试使用:

SELECT linkorder
    ,Row_Number() OVER (
        PARTITION BY linkorder ORDER BY linkorder DESC
        ) AS RowNum
FROM u_links

enter image description here


6
微软有一个非常好的指南,介绍如何删除重复项。请查看http://support.microsoft.com/kb/139444
简而言之,当您只需要删除几行时,以下是最简单的删除重复项的方法:
SET rowcount 1;
DELETE FROM t1 WHERE myprimarykey=1;

myprimarykey是该行��标识符。

我将rowcount设置为1,因为我只有两行重复。如果我有3行重复,则会将rowcount设置为2,以便删除它看到的前两行,并仅在表t1中留下一行。


1
如果我有一万行数据,如何知道其中有多少行是重复的? - Fearghal
@Fearghal 试试这个语句:"select primaryKey, count(*) from myTable group by primaryKey;" - dev4life
1
但是如果有不同数量的重复行呢?例如,行a有2条记录,行b有5条记录,而行c没有重复记录。 - thermite
1
如果只有一部分行存在重复,并且其中某些重复项重复两次,而某些重复三次或四次呢? - thermite
@user2070775,我没有注意到你说“只有几行需要删除”的部分。此外,页面上还有一个关于set rowcount的警告,在sql的未来版本中,它将不会影响update或delete语句。 - thermite
在这种情况下,我猜编写一个脚本会更方便,而不是试图在SQL中手动执行。该脚本将选择重复的行,计算重复次数并执行“SET rowcount $numer_of_dulicated-1; DELETE FROM t1 WHERE myprimarykey=$duplicated_id_value;” - dev4life

4
在尝试上面提供的解决方法后,我发现这种方法适用于小中型表格。但是对于非常大的表格,我可以建议您使用另一种解决方案,因为它需要进行迭代。
以下是详细步骤:
  1. 删除所有与LargeSourceTable相关的依赖视图
  2. 您可以使用SQL管理工作室找到依赖项,右键单击表格,然后单击“查看依赖项”
  3. 重命名表格:
  4. sp_rename 'LargeSourceTable','LargeSourceTable_Temp'; GO
  5. 重新创建LargeSourceTable,但现在要添加一个主键,将定义重复值的所有列添加WITH(IGNORE_DUP_KEY = ON)
  6. 例如:

    CREATE TABLE [dbo]。[LargeSourceTable] ( ID int IDENTITY(1,1), [CreateDate] DATETIME CONSTRAINT [DF_LargeSourceTable_CreateDate] DEFAULT (getdate()) NOT NULL, [Column1] CHAR (36) NOT NULL, [Column2] NVARCHAR (100) NOT NULL, [Column3] CHAR (36) NOT NULL, PRIMARY KEY (Column1, Column2) WITH (IGNORE_DUP_KEY = ON) ); GO

  7. 再次创建您在第一步删除的视图以针对新创建的表格

  8. 现在,运行以下SQL脚本,您将在每页1,000,000行中看到结果,您可以更改每页的行数以更频繁地查看结果。

  9. 请注意,我设置了IDENTITY_INSERT,因为其中一个列包含自动增量ID,我也正在复制它

SET IDENTITY_INSERT LargeSourceTable ON DECLARE @PageNumber AS INT, @RowspPage AS INT DECLARE @TotalRows AS INT declare @dt varchar(19) SET @PageNumber = 0 SET @RowspPage = 1000000 select @TotalRows = count (*) from LargeSourceTable_TEMP

While ((@PageNumber - 1) * @RowspPage < @TotalRows )
Begin
    begin transaction tran_inner
        ; with cte as
        (
            SELECT * FROM LargeSourceTable_TEMP ORDER BY ID
            OFFSET ((@PageNumber) * @RowspPage) ROWS
            FETCH NEXT @RowspPage ROWS ONLY
        )

        INSERT INTO LargeSourceTable 
        (
             ID                     
            ,[CreateDate]       
            ,[Column1]   
            ,[Column2] 
            ,[Column3]       
        )       
        select 
             ID                     
            ,[CreateDate]       
            ,[Column1]   
            ,[Column2] 
            ,[Column3]       
        from cte

    commit transaction tran_inner

    PRINT 'Page: ' + convert(varchar(10), @PageNumber)
    PRINT 'Transfered: ' + convert(varchar(20), @PageNumber * @RowspPage)
    PRINT 'Of: ' + convert(varchar(20), @TotalRows)

    SELECT @dt = convert(varchar(19), getdate(), 121)
    RAISERROR('Inserted on: %s', 0, 1, @dt) WITH NOWAIT
    SET @PageNumber = @PageNumber + 1
End

SET IDENTITY_INSERT LargeSourceTable OFF


4
with myCTE
as

(
select productName,ROW_NUMBER() over(PARTITION BY productName order by slno) as Duplicate from productDetails
)
Delete from myCTE where Duplicate>1

在数百万条记录中快速地运行良好。 - Isaac Gachugu

2
-- this query will keep only one instance of a duplicate record.
;WITH cte
     AS (SELECT ROW_NUMBER() OVER (PARTITION BY col1, col2, col3-- based on what? --can be multiple columns
                                       ORDER BY ( SELECT 0)) RN
         FROM   Mytable)



delete  FROM cte
WHERE  RN > 1

2
你需要按照字段对重复记录进行分组,然后保留一条记录并删除其余记录。 例如:
DELETE prg.Person WHERE Id IN (
SELECT dublicateRow.Id FROM
(
select MIN(Id) MinId, NationalCode
 from  prg.Person group by NationalCode  having count(NationalCode ) > 1
 ) GroupSelect
 JOIN  prg.Person dublicateRow ON dublicateRow.NationalCode = GroupSelect.NationalCode 
 WHERE dublicateRow.Id <> GroupSelect.MinId)

2

这可能对你的情况有所帮助

DELETE t1 FROM table t1 INNER JOIN table t2 WHERE t1.id > t2.id AND t1.col1 = t2.col1 

1
由于原问题中表格没有ID,我认为这种方法并不能解决问题。 - JeffryHouser
1
如果你仔细阅读问题,你会发现其中有 id - Ankit Jindal

2

从一个包含数百万条记录的大表中删除重复数据可能需要很长时间。我建议您将所选行批量插入到临时表中,而不是直接删除。

修改后的答案:批量插入选定行到临时表中,而非直接删除,可以更快地删除包含数百万条记录的大表中的重复数据。

--REWRITING YOUR CODE(TAKE NOTE OF THE 3RD LINE) 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;

2
要在没有唯一行ID的情况下删除SQL Server中的重复行,可以使用ROW_NUMBER()函数与公共表达式(CTE)结合使用来识别和删除重复行。以下是一个示例查询,应该能够实现所需的结果:
WITH CTE AS (
    SELECT col1, col2, col3, col4, col5, col6, col7,
           ROW_NUMBER() OVER (PARTITION BY col1, col2, col3, col4, col5, col6, col7 ORDER BY (SELECT 0)) AS RowNumber
    FROM YourTable
)
DELETE FROM CTE WHERE RowNumber > 1;

将YourTable替换为您表的实际名称。该查询根据col1、col2、col3、col4、col5、col6和col7中值的组合,为每个集合内的重复行分配一个行号。然后删除行号大于1的行。

您可以利用dbForge Studio的 SQL编辑器来执行查询并高效处理各种其他数据库管理任务。


1

请在SELECT命令后简单地加上关键字DISTINCT,例如:

SELECT DISTICNT ColumnOne, ColumnTwo, ColumnThree
 FROM YourTable

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