如何删除重复的行?

How can I remove duplicate rows?

提问人:Seibar 提问时间:8/21/2008 最后编辑:TylerHSeibar 更新时间:10/8/2022 访问量:1355421

问:

我需要从相当大的 SQL Server 表(即 300,000+ 行)中删除重复的行。

当然,由于标识字段的存在,这些行不会是完全重复的。RowID

我的桌子

RowID int not null identity(1,1) primary key,
Col1 varchar(20) not null,
Col2 varchar(2048) not null,
Col3 tinyint not null

我该怎么做?

SQL-SERVER T-SQL 重复项

评论

15赞 Craig Ringer 8/26/2013
PostgreSQL用户阅读本文的快速提示(很多,按其链接频率):Pg不会将CTE术语公开为可更新的视图,因此您不能直接使用CTE术语。查看 stackoverflow.com/q/18439054/398670DELETE FROM
0赞 maf-soft 10/29/2013
@CraigRinger Sybase 也是如此 - 我在这里收集了剩余的解决方案(也应该对 PG 和其他解决方案有效:stackoverflow.com/q/19544489/1855801(如果有,只需将函数替换为 RowID 列)ROWID()
14赞 Jeff Davis 12/4/2013
只是为了在这里添加一个警告。在运行任何重复数据消除过程时,请务必先仔细检查要删除的内容!这是意外删除优质数据非常常见的领域之一。

答:

159赞 Jon Galloway 8/21/2008 #1

Microsoft 支持网站上有一篇关于删除重复项的好文章。这是相当保守的 - 他们让你在单独的步骤中完成所有事情 - 但它应该适用于大型桌子。

我过去曾使用过自连接来做到这一点,尽管它可能被 HAVING 子句美化:

DELETE dupes
FROM MyTable dupes, MyTable fullTable
WHERE dupes.dupField = fullTable.dupField 
AND dupes.secondDupField = fullTable.secondDupField 
AND dupes.uniqueField > fullTable.uniqueField

评论

0赞 Drunken M 2/12/2020
完善!我发现这是在我的旧MariaDB 10.1.xx版本上删除重复行的最有效方法。谢谢!
0赞 Marc 2/22/2020
更简单易懂!
0赞 user3065757 4/3/2021
我有一个疑问,在您的 sql 查询中,为什么您不在“DELETE”之后使用“From”关键字?我已经从许多其他解决方案中看到过。
11赞 Craig 8/21/2008 #2

这是另一篇关于删除重复项的好文章。

它讨论了为什么它很难:“SQL基于关系代数,在关系代数中不能出现重复,因为集合中不允许重复。"

临时表解决方案和两个 mysql 示例。

将来,您将在数据库级别或从应用程序的角度阻止它。我建议数据库级别,因为您的数据库应该负责维护引用完整性,开发人员只会造成问题;)

评论

1赞 Andrew 10/18/2011
SQL 基于多集。但即使它基于集合,这两个元组(1,a)和(2,a)也是不同的。
1192赞 Mark Brackett 8/21/2008 #3

假设没有 null,则使用唯一列,并将 RowId 作为要保留的行。然后,只需删除没有行 ID 的所有内容:GROUP BYSELECTMIN (or MAX)

DELETE FROM MyTable
LEFT OUTER JOIN (
   SELECT MIN(RowId) as RowId, Col1, Col2, Col3 
   FROM MyTable 
   GROUP BY Col1, Col2, Col3
) as KeepRows ON
   MyTable.RowId = KeepRows.RowId
WHERE
   KeepRows.RowId IS NULL

如果您有 GUID 而不是整数,则可以将

MIN(RowId)

CONVERT(uniqueidentifier, MIN(CONVERT(char(36), MyGuidColumn)))

评论

349赞 Georg Schölly 9/23/2010
这也行得通吗?DELETE FROM MyTable WHERE RowId NOT IN (SELECT MIN(RowId) FROM MyTable GROUP BY Col1, Col2, Col3);
10赞 Martin Smith 1/14/2011
@Andriy - 在 SQL Server 中效率低于 sqlinthewild.co.za/index.php/2010/03/23/...同一网站还比较了 vs .sqlinthewild.co.za/index.php/2010/02/18/not-exists-vs-not-in在 3 个中,我认为表现最好。这三个人都会生成一个带有自我加入的计划,尽管这是可以避免的。LEFT JOINNOT EXISTSNOT INNOT EXISTSNOT EXISTS
13赞 Andriy M 1/14/2011
@Martin,@Georg:所以,我做了一个小测试。创建并填充了一个大表,如下所述:sqlinthewild.co.za/index.php/2010/03/23/...然后生成两个 SELECT,一个使用 LEFT JOIN + WHERE IS NULL 技术,另一个使用 NOT IN 一个。然后我继续执行计划,你猜怎么着?LEFT JOIN 的查询成本为 18%,而 NOT IN 的查询成本为 82%,这对我来说是一个很大的惊喜。我可能做了一些我不应该做的事情,反之亦然,如果这是真的,我真的很想知道。
17赞 Philip Kearns 5/29/2013
@GeorgSchölly提供了一个优雅的答案。我已经在一个表上使用了它,我的一个 PHP 错误创建了重复的行。
13赞 levininja 11/7/2013
对不起,为什么语法是正确的?我没有看到将表名放在此处文档中的选项之后。对不起,如果这对其他人来说是显而易见的;我是SQL的新手,只是想学习。比它为什么起作用更重要的是:在那里包含表的名称有什么区别?DELETE MyTable FROM MyTableDELETE
11赞 Jacob Proffitt 8/21/2008 #4

哦,当然。使用临时表。如果你想要一个“有效”的、性能不高的语句,你可以这样做:

DELETE FROM MyTable WHERE NOT RowID IN
    (SELECT 
        (SELECT TOP 1 RowID FROM MyTable mt2 
        WHERE mt2.Col1 = mt.Col1 
        AND mt2.Col2 = mt.Col2 
        AND mt2.Col3 = mt.Col3) 
    FROM MyTable mt)

基本上,对于表中的每一行,子选择会查找与所考虑的行完全相同的所有行的顶部 RowID。因此,您最终会得到一个表示“原始”非重复行的 RowID 列表。

7赞 DrPizza 8/21/2008 #5

从应用程序层面(不幸的是)。我同意防止重复的正确方法是在数据库级别通过使用唯一索引,但在 SQL Server 2005 中,索引只允许为 900 字节,而我的 varchar(2048) 字段将其吹走了。

我不知道它的性能如何,但我认为你可以编写一个触发器来强制执行这一点,即使你不能直接使用索引来做到这一点。像这样:

-- given a table stories(story_id int not null primary key, story varchar(max) not null)
CREATE TRIGGER prevent_plagiarism 
ON stories 
after INSERT, UPDATE 
AS 
    DECLARE @cnt AS INT 

    SELECT @cnt = Count(*) 
    FROM   stories 
           INNER JOIN inserted 
                   ON ( stories.story = inserted.story 
                        AND stories.story_id != inserted.story_id ) 

    IF @cnt > 0 
      BEGIN 
          RAISERROR('plagiarism detected',16,1) 

          ROLLBACK TRANSACTION 
      END 

另外,varchar(2048) 对我来说听起来很可疑(生活中有些东西是 2048 字节,但这并不常见);它真的不应该是 varchar(max) 吗?

9赞 Kamil 5/8/2009 #6
  1. 创建具有相同结构的新空白表

  2. 像这样执行查询

    INSERT INTO tc_category1
    SELECT *
    FROM tc_category
    GROUP BY category_id, application_id
    HAVING count(*) > 1
    
  3. 然后执行此查询

    INSERT INTO tc_category1
    SELECT *
    FROM tc_category
    GROUP BY category_id, application_id
    HAVING count(*) = 1
    
11赞 codegoalie 12/11/2009 #7

我有一个表,我需要保留不重复的行。 我不确定速度或效率。

DELETE FROM myTable WHERE RowID IN (
  SELECT MIN(RowID) AS IDNo FROM myTable
  GROUP BY Col1, Col2, Col3
  HAVING COUNT(*) = 2 )

评论

7赞 Martin Smith 10/3/2010
这假设最多有 1 个重复项。
0赞 Philipp M 10/7/2014
为什么不呢?HAVING COUNT(*) > 1
794赞 Martin Smith 9/29/2010 #8

另一种可能的方法是

; 

--Ensure that any immediately preceding statement is terminated with a semicolon above
WITH cte
     AS (SELECT ROW_NUMBER() OVER (PARTITION BY Col1, Col2, Col3 
                                       ORDER BY ( SELECT 0)) RN
         FROM   #MyTable)
DELETE FROM cte
WHERE  RN > 1;

我在上面使用,因为在出现平局时保留哪一行是任意的。ORDER BY (SELECT 0)

例如,要按顺序保留最新的,您可以使用RowIDORDER BY RowID DESC

执行计划

此操作的执行计划通常比公认的答案更简单、更有效,因为它不需要自连接。

执行计划

然而,情况并非总是如此。解决方案可能首选的一个位置是优先选择哈希聚合而不是流聚合的情况。GROUP BY

该解决方案将始终提供几乎相同的计划,而策略则更加灵活。ROW_NUMBERGROUP BY

执行计划

可能有利于哈希聚合方法的因素是

  • 分区列上没有有用的索引
  • 组相对较少,每组重复项相对较多

在第二种情况的极端版本中(如果组很少,每个组中有许多重复项),也可以考虑简单地插入要保留的行到新表中,然后-ing原始表并将它们复制回去,以最大程度地减少日志记录,而不是删除非常高比例的行。TRUNCATE

评论

31赞 BrunoLM 11/16/2010
如果我可以补充:接受的答案不适用于使用 .这个要简单得多,可以在任何桌子上完美运行。谢谢马丁。uniqueidentifier
15赞 Mikael Eliasson 7/20/2011
这真是一个了不起的答案!当我删除旧的 PK 时,它起作用了,然后我才意识到那里有重复的地方。+100
12赞 Nick Chammas 6/6/2012
我建议在 DBA.SE 上提出然后回答这个问题(有这个答案)。然后我们可以将其添加到我们的规范答案列表中
17赞 vossad01 3/5/2013
与公认的答案不同,这也适用于没有键 () 进行比较的表。RowId
8赞 David 3/24/2015
另一方面,这并不适用于所有 SQL Server 版本
75赞 SoftwareGeek 9/30/2010 #9
delete t1
from table t1, table t2
where t1.columnA = t2.columnA
and t1.rowid>t2.rowid

Postgres:

delete
from table t1
using table t2
where t1.columnA = t2.columnA
and t1.rowid > t2.rowid

评论

0赞 user692942 3/8/2016
为什么要在 SQL Server 问题上发布 Postgres 解决方案?
3赞 Gabriel 1/15/2018
@Lankymart 因为 postgres 用户也来到这里。看看这个答案的分数。
2赞 Gabriel 1/16/2018
我在一些流行的SQL问题中看到了这一点,如这里、这里这里OP得到了他的答案,其他人也得到了一些帮助。恕我直言,没问题。
0赞 user3065757 4/3/2021
在一个查询中,您在删除后使用“From”,而在一个查询中,您没有使用“From”,逻辑是什么?
103赞 gngolakia 11/23/2011 #10

以下查询可用于删除重复的行。此示例中的表作为标识列,具有重复数据的列是 和 。IDColumn1Column2Column3

DELETE FROM TableName
WHERE  ID NOT IN (SELECT MAX(ID)
                  FROM   TableName
                  GROUP  BY Column1,
                            Column2,
                            Column3
                  /*Even if ID is not null-able SQL Server treats MAX(ID) as potentially
                    nullable. Because of semantics of NOT IN (NULL) including the clause
                    below can simplify the plan*/
                  HAVING MAX(ID) IS NOT NULL) 

以下脚本显示了 、 在一个查询中的用法,并返回包含重复列及其计数的结果。GROUP BYHAVINGORDER BY

SELECT YourColumnName,
       COUNT(*) TotalCount
FROM   YourTableName
GROUP  BY YourColumnName
HAVING COUNT(*) > 1
ORDER  BY COUNT(*) DESC 

评论

1赞 D.Rosado 6/13/2012
第一个脚本的MySQL错误“您不能在FROM子句中指定目标表'TableName'进行更新”
0赞 parvus 1/3/2013
除了已经报告的错误 D.Rosado 之外,您的第一个查询也非常慢。相应的 SELECT 查询在我的设置上花费的时间比接受的答案长 +- 20 倍。
8赞 Martin Smith 1/5/2013
@parvus - 问题标记为 SQL Server,而不是 MySQL。语法在 SQL Server 中很好。此外,MySQL在优化子查询方面是出了名的糟糕,例如,请参阅此处。这个答案在 SQL Server 中很好。事实上,通常比 .我会在查询中添加一个,尽管从语义上讲它不应该是必需的,因为这可以改进这里的计划示例NOT INOUTER JOIN ... NULLHAVING MAX(ID) IS NOT NULL
2赞 nortally 5/6/2014
在 PostgreSQL 8.4 中效果很好。
9赞 Sudhakar NV 2/8/2012 #11

通过使用下面的查询,我们可以基于单列或多列删除重复的记录。下面的查询基于两列进行删除。表名为:和列名testingempno,empname

DELETE FROM testing WHERE empno not IN (SELECT empno FROM (SELECT empno, ROW_NUMBER() OVER (PARTITION BY empno ORDER BY empno) 
AS [ItemNumber] FROM testing) a WHERE ItemNumber > 1)
or empname not in
(select empname from (select empname,row_number() over(PARTITION BY empno ORDER BY empno) 
AS [ItemNumber] FROM testing) a WHERE ItemNumber > 1)
6赞 AnandPhadke 7/11/2012 #12
CREATE TABLE car(Id int identity(1,1), PersonId int, CarId int)

INSERT INTO car(PersonId,CarId)
VALUES(1,2),(1,3),(1,2),(2,4)

--SELECT * FROM car

;WITH CTE as(
SELECT ROW_NUMBER() over (PARTITION BY personid,carid order by personid,carid) as rn,Id,PersonID,CarId from car)

DELETE FROM car where Id in(SELECT Id FROM CTE WHERE rn>1)
17赞 heta77 10/10/2012 #13
SELECT  DISTINCT *
      INTO tempdb.dbo.tmpTable
FROM myTable

TRUNCATE TABLE myTable
INSERT INTO myTable SELECT * FROM tempdb.dbo.tmpTable
DROP TABLE tempdb.dbo.tmpTable

评论

5赞 Sameer Alibhai 6/27/2013
如果对 myTable 有外键引用,则截断将不起作用。
7赞 Evgueny Sedov 1/31/2013 #14

我会提到这种方法,因为它可能会有所帮助,并且适用于所有 SQL 服务器: 通常只有一个 - 两个重复项,并且 ID 和重复项计数是已知的。在这种情况下:

SET ROWCOUNT 1 -- or set to number of rows to be deleted
delete from myTable where RowId = DuplicatedID
SET ROWCOUNT 0
24赞 JuanJo 2/6/2013 #15

Quick and Dirty 删除完全重复的行(对于小表):

select  distinct * into t2 from t1;
delete from t1;
insert into t1 select *  from t2;
drop table t2;

评论

3赞 Dennis Jaheruddin 7/16/2015
请注意,该问题实际上指定了非精确重复(由于行 ID)。
0赞 David R Tribble 8/28/2020
您还必须使用 处理标识(键)列。set identity_insert t1 on
13赞 Nitish Pareek 8/7/2013 #16

另一个简单的解决方案可以在这里粘贴的链接中找到。这个很容易掌握,似乎对大多数类似的问题都有效。虽然它适用于 SQL Server,但使用的概念是可以接受的。

以下是链接页面的相关部分:

请考虑以下数据:

EMPLOYEE_ID ATTENDANCE_DATE
A001    2011-01-01
A001    2011-01-01
A002    2011-01-01
A002    2011-01-01
A002    2011-01-01
A003    2011-01-01

那么我们如何删除这些重复的数据呢?

首先,使用以下代码在该表中插入标识列:

ALTER TABLE dbo.ATTENDANCE ADD AUTOID INT IDENTITY(1,1)  

使用以下代码解决此问题:

DELETE FROM dbo.ATTENDANCE WHERE AUTOID NOT IN (SELECT MIN(AUTOID) _
    FROM dbo.ATTENDANCE GROUP BY EMPLOYEE_ID,ATTENDANCE_DATE) 

评论

1赞 Andriy M 8/7/2013
“易于掌握”、“似乎有效”,但只字未提该方法的内容。试想一下,链接变得无效,那么知道该方法易于掌握且有效又有什么用呢?请考虑将方法描述的基本部分添加到您的帖子中,否则这不是答案。
0赞 Jeff Davis 11/6/2013
此方法对于尚未定义标识的表非常有用。通常,您需要删除重复项才能定义主键!
0赞 Martin Smith 3/2/2014
@JeffDavis - 该版本适用于这种情况,而无需在开始之前添加新列。ROW_NUMBER
42赞 Syed Mohamed 9/10/2013 #17

这将删除除第一行之外的重复行

DELETE
FROM
    Mytable
WHERE
    RowID NOT IN (
        SELECT
            MIN(RowID)
        FROM
            Mytable
        GROUP BY
            Col1,
            Col2,
            Col3
    )

参考 (http://www.codeproject.com/Articles/157977/Remove-Duplicate-Rows-from-a-Table-in-SQL-Server)

评论

11赞 Ritesh 3/1/2016
对于mysql,它将给出错误:错误代码:1093。不能在 FROM 子句中指定目标表“Mytable”进行更新。但这个小改动适用于 mysql: DELETE FROM Mytable WHERE RowID NOT IN ( SELECT ID FROM (SELECT MIN(RowID) as id from Mytable GROUP BY Col1,Col2,Col3) AS TEMP)
10赞 Ismail Yavuz 9/18/2013 #18

另一种方法是创建一个具有相同字段和唯一索引的新表。然后将所有数据从旧表移动到新表。自动 SQL SERVER 忽略(还有一个选项,说明如果存在重复值该怎么办:忽略、中断或 sth)重复值。因此,我们有相同的表,没有重复的行。如果您不想要唯一索引,则可以在传输数据后将其删除

特别是对于较大的表,您可以使用 DTS(用于导入/导出数据的 SSIS 包)将所有数据快速传输到新的唯一索引表。对于 700 万行,只需几分钟。

7赞 Teena 10/3/2013 #19
DELETE
FROM
    table_name T1
WHERE
    rowid > (
        SELECT
            min(rowid)
        FROM
            table_name T2
        WHERE
            T1.column_name = T2.column_name
    );

评论

0赞 Nagaraj M 8/1/2017
嗨,Teena,您在删除注释后错过了表 Alice 名称 T1,否则将导致语法异常。
6赞 Jayron Soares 1/2/2014 #20
DELETE 
FROM MyTable
WHERE NOT EXISTS (
              SELECT min(RowID)
              FROM Mytable
              WHERE (SELECT RowID 
                     FROM Mytable
                     GROUP BY Col1, Col2, Col3
                     ))
               );
15赞 Ruben Verschueren 1/27/2014 #21

我想我会分享我的解决方案,因为它在特殊情况下有效。 就我而言,具有重复值的表没有外键(因为这些值是从另一个数据库复制的)。

begin transaction
-- create temp table with identical structure as source table
Select * Into #temp From tableName Where 1 = 2

-- insert distinct values into temp
insert into #temp 
select distinct * 
from  tableName

-- delete from source
delete from tableName 

-- insert into source from temp
insert into tableName 
select * 
from #temp

rollback transaction
-- if this works, change rollback to commit and execute again to keep you changes!!

PS:在处理这样的事情时,我总是使用事务,这不仅确保了所有内容都作为一个整体执行,而且还允许我在不冒任何风险的情况下进行测试。但当然,无论如何你都应该进行备份,以确保......

21赞 James Errico 3/1/2014 #22

我更喜欢 subquery\having count(*) > 1 解决方案而不是内部连接,因为我发现它更容易阅读,并且很容易转换为 SELECT 语句以在运行之前验证将删除的内容。

--DELETE FROM table1 
--WHERE id IN ( 
     SELECT MIN(id) FROM table1 
     GROUP BY col1, col2, col3 
     -- could add a WHERE clause here to further filter
     HAVING count(*) > 1
--)

评论

0赞 Sandy 5/16/2015
它不会删除内部查询中显示的所有记录吗?我们只需要删除重复项并保留原始内容。
3赞 James Errico 5/18/2015
根据 select 子句中的 min(id),您只返回 id 最低的那个。
2赞 James Errico 5/19/2015
取消注释掉查询的第一行、第二行和最后一行。
7赞 Chloe 11/7/2015
这不会清除所有重复项。如果您有 3 行是重复的,它将只选择带有 MIN(id) 的行,并删除该行,留下两行是重复的。
2赞 Chloe 11/8/2015
尽管如此,我最终还是一遍又一遍地重复使用这句话,这样它实际上会取得进展,而不是让连接超时或计算机进入睡眠状态。我将其更改为消除后者的重复项,并添加到内部查询中,因此它不必扫描整个表。这比其他答案的进展要快得多,后者似乎会持续数小时。将表修剪到可管理的大小后,可以完成其他查询。提示:确保 col1/col2/col3 有分组依据的索引。MAX(id)LIMIT 1000000
47赞 Jithin Shaji 5/21/2014 #23
DELETE LU 
FROM   (SELECT *, 
               Row_number() 
                 OVER ( 
                   partition BY col1, col1, col3 
                   ORDER BY rowid DESC) [Row] 
        FROM   mytable) LU 
WHERE  [row] > 1 

评论

1赞 Amit 10/22/2016
我在 azure SQL DW 上收到此消息:DELETE 语句中当前不支持 FROM 子句。
14赞 Ostati 11/14/2014 #24

使用 CTE。这个想法是联接形成重复记录的一列或多列,然后删除您喜欢的任何列:

;with cte as (
    select 
        min(PrimaryKey) as PrimaryKey
        UniqueColumn1,
        UniqueColumn2
    from dbo.DuplicatesTable 
    group by
        UniqueColumn1, UniqueColumn1
    having count(*) > 1
)
delete d
from dbo.DuplicatesTable d 
inner join cte on 
    d.PrimaryKey > cte.PrimaryKey and
    d.UniqueColumn1 = cte.UniqueColumn1 and 
    d.UniqueColumn2 = cte.UniqueColumn2;

评论

1赞 Justin R. 3/17/2016
我认为您在 JOIN 中缺少一个 AND。
14赞 Draško 12/11/2014 #25

这个查询对我来说显示出非常好的性能:

DELETE tbl
FROM
    MyTable tbl
WHERE
    EXISTS (
        SELECT
            *
        FROM
            MyTable tbl2
        WHERE
            tbl2.SameValue = tbl.SameValue
        AND tbl.IdUniqueValue < tbl2.IdUniqueValue
    )

它在 30 秒多一点的时间内从 2M 表中删除了 2M 行(50% 重复)

6赞 Lauri Lubi 1/1/2015 #26

我想要预览要删除的行,并控制要保留哪些重复行。查看 http://developer.azurewebsites.net/2014/09/better-sql-group-by-find-duplicate-data/

with MYCTE as (
  SELECT ROW_NUMBER() OVER (
    PARTITION BY DuplicateKey1
                ,DuplicateKey2 -- optional
    ORDER BY CreatedAt -- the first row among duplicates will be kept, other rows will be removed
  ) RN
  FROM MyTable
)
DELETE FROM MYCTE
WHERE RN > 1

评论

0赞 Vikas kumar 6/17/2022
从用户中删除 u1 u1 加入用户 u2 其中 u1.id > u2.id 和 u1.email=u2.email
38赞 Shamseer K 5/19/2015 #27

我更喜欢 CTE 从 sql server 表中删除重复的行

强烈建议关注这篇文章 ::http://codaffection.com/sql-server-article/delete-duplicate-rows-in-sql-server/

通过保持原创

WITH CTE AS
(
SELECT *,ROW_NUMBER() OVER (PARTITION BY col1,col2,col3 ORDER BY col1,col2,col3) AS RN
FROM MyTable
)

DELETE FROM CTE WHERE RN<>1

不保持原样

WITH CTE AS
(SELECT *,R=RANK() OVER (ORDER BY col1,col2,col3)
FROM MyTable)
 
DELETE CTE
WHERE R IN (SELECT R FROM CTE GROUP BY R HAVING COUNT(*)>1)

评论

0赞 user3065757 4/3/2021
在一个查询中,您在删除后使用“from”,而在另一个查询中,“from”不存在,这是什么,我很困惑?
12赞 Haris N I 7/23/2015 #28

使用这个

WITH tblTemp as
(
SELECT ROW_NUMBER() Over(PARTITION BY Name,Department ORDER BY Name)
   As RowNumber,* FROM <table_name>
)
DELETE FROM tblTemp where RowNumber >1
1赞 Chanukya 12/16/2015 #29
alter table MyTable add sno int identity(1,1)
    delete from MyTable where sno in
    (
    select sno from (
    select *,
    RANK() OVER ( PARTITION BY RowID,Col3 ORDER BY sno DESC )rank
    From MyTable
    )T
    where rank>1
    )

    alter table MyTable 
    drop  column sno
0赞 Hamit YILDIRIM 1/12/2016 #30

现在让我们看一下elasticalsearch表,该表有重复的行,Id是相同的uniq字段。我们知道,如果某个 id 按照组条件存在,那么我们可以删除该组范围之外的其他行。我的方式表明了这个标准。

这个线程的很多情况都处于与我类似的状态。只需根据删除重复(重复)行的情况更改目标组条件即可。

DELETE 
FROM elasticalsearch
WHERE Id NOT IN 
               (SELECT min(Id)
                     FROM elasticalsearch
                     GROUP BY FirmId,FilterSearchString
                     ) 

干杯

评论

3赞 Wai Ha Lee 1/19/2016
你能解释一下你的代码是如何/为什么工作的吗?这将使 OP 和其他人能够理解和应用您的方法(如果适用)。不鼓励使用纯代码答案,否则可能会被删除。— 审查期间
1赞 Hamit YILDIRIM 1/19/2016
好的,我解释了我的 answwer Wai Ha Lee 代码的 inspute 显示了所有细节
8赞 yuvi 2/2/2016 #31

另一种方法:--

DELETE A
FROM   TABLE A,
       TABLE B
WHERE  A.COL1 = B.COL1
       AND A.COL2 = B.COL2
       AND A.UNIQUEFIELD > B.UNIQUEFIELD 

评论

0赞 user692942 3/8/2016
与2008年8月20日的现有答案有什么不同?- stackoverflow.com/a/18934/692942
1赞 Brett Ryan 6/7/2016 #32

有时,在记录日期时使用软删除机制来指示已删除的日期。在这种情况下,可以使用语句根据重复条目更新此字段。UPDATE

UPDATE MY_TABLE
   SET DELETED = getDate()
 WHERE TABLE_ID IN (
    SELECT x.TABLE_ID
      FROM MY_TABLE x
      JOIN (SELECT min(TABLE_ID) id, COL_1, COL_2, COL_3
              FROM MY_TABLE d
             GROUP BY d.COL_1, d.COL_2, d.COL_3
            HAVING count(*) > 1) AS d ON d.COL_1 = x.COL_1
                                     AND d.COL_2 = x.COL_2
                                     AND d.COL_3 = x.COL_3
                                     AND d.TABLE_ID <> x.TABLE_ID
             /*WHERE x.COL_4 <> 'D' -- Additional filter*/)

这种方法对于包含 ~3000 万行的相当适度的表很有帮助,重复量和重复量都很高。

13赞 Harikesh Yadav 9/28/2016 #33

这是删除重复记录的最简单方法

 DELETE FROM tblemp WHERE id IN 
 (
  SELECT MIN(id) FROM tblemp
   GROUP BY  title HAVING COUNT(id)>1
 )

评论

2赞 crellee 1/18/2018
为什么有人对此投赞成票?如果您有两个以上的相同 ID,这将不起作用。改为写:delete from tblemp where id not in (select min(id) from tblemp group by title)
30赞 Shaini Sinha 12/29/2016 #34

要获取重复的行:

SELECT
name, email, COUNT(*)
FROM 
users
GROUP BY
name, email
HAVING COUNT(*) > 1

要删除重复的行:

DELETE users 
WHERE rowid NOT IN 
(SELECT MIN(rowid)
FROM users
GROUP BY name, email);      

评论

0赞 Íhor Mé 8/9/2019
对于MySQL用户,请注意,首先它必须是,其次,它不会起作用,因为你不能从你正在处理的同一个表中。在MySQL中,这爆炸了。DELETE FROMSELECTDELETEMySQL error 1093
0赞 Oliver Schimmer 8/16/2021
我认为比使用在某些系统(例如.SQL服务器)上也不起作用的相当狭温的可接受答案要合理得多。如果遇到上述限制,则始终可以将选择结果保存到临时 TABLE 变量中:然后DELETE FROM ... LEFT OUTER JOINDECLARE @idsToKeep TABLE(rowid INT);INSERT INTO @idsToKeep(rowid) SELECT MIN... GROUP BY ...DELETE users WHERE rowid NOT IN (SELECT rowid FROM @idsToKeep);
1赞 Jakub Ojmucianski 4/13/2017 #35

我知道这个问题已经得到解答,但是我已经创建了非常有用的sp,它将为表重复项创建一个动态删除语句:

    CREATE PROCEDURE sp_DeleteDuplicate @tableName varchar(100), @DebugMode int =1
AS 
BEGIN
SET NOCOUNT ON;

IF(OBJECT_ID('tempdb..#tableMatrix') is not null) DROP TABLE #tableMatrix;

SELECT ROW_NUMBER() OVER(ORDER BY name) as rn,name into #tableMatrix FROM sys.columns where [object_id] = object_id(@tableName) ORDER BY name

DECLARE @MaxRow int = (SELECT MAX(rn) from #tableMatrix)
IF(@MaxRow is null)
    RAISERROR  ('I wasn''t able to find any columns for this table!',16,1)
ELSE 
    BEGIN
DECLARE @i int =1 
DECLARE @Columns Varchar(max) ='';

WHILE (@i <= @MaxRow)
BEGIN 
    SET @Columns=@Columns+(SELECT '['+name+'],' from #tableMatrix where rn = @i)

    SET @i = @i+1;
END

---DELETE LAST comma
SET @Columns = LEFT(@Columns,LEN(@Columns)-1)

DECLARE @Sql nvarchar(max) = '
WITH cteRowsToDelte
     AS (
SELECT ROW_NUMBER() OVER (PARTITION BY '+@Columns+' ORDER BY ( SELECT 0)) as rowNumber,* FROM '+@tableName
+')

DELETE FROM cteRowsToDelte
WHERE  rowNumber > 1;
'
SET NOCOUNT OFF;
    IF(@DebugMode = 1)
       SELECT @Sql
    ELSE
       EXEC sp_executesql @Sql
    END
END

因此,如果您创建这样的表:

IF(OBJECT_ID('MyLitleTable') is not null)
    DROP TABLE MyLitleTable 


CREATE TABLE MyLitleTable
(
    A Varchar(10),
    B money,
    C int
)
---------------------------------------------------------

    INSERT INTO MyLitleTable VALUES
    ('ABC',100,1),
    ('ABC',100,1), -- only this row should be deleted
    ('ABC',101,1),
    ('ABC',100,2),
    ('ABCD',100,1)

    -----------------------------------------------------------

     exec sp_DeleteDuplicate 'MyLitleTable',0

它将从您的表中删除所有重复项。如果您在没有第二个参数的情况下运行它,它将返回要运行的 SQL 语句。

如果需要排除任何列,只需在调试模式下运行它,获取代码并根据需要对其进行修改。

0赞 Selim Reza 6/10/2018 #36

我认为这会有所帮助。这里,ROW_NUMBER() OVER(PARTITION BY res1.标题 ORDER BY res1.Id)as num 已用于区分重复行。

delete FROM
(SELECT res1.*,ROW_NUMBER() OVER(PARTITION BY res1.Title ORDER BY res1.Id)as num
 FROM 
(select * from [dbo].[tbl_countries])as res1
)as res2
WHERE res2.num > 1

评论

0赞 Michael 6/22/2018
你能描述一下是什么让你的答案与这个不同吗?
1赞 Suraj Kumar 10/29/2018 #37

如果重复行中的所有列都相同,则可以使用以下查询来删除重复的记录。

SELECT DISTINCT * INTO #TemNewTable FROM #OriginalTable
TRUNCATE TABLE #OriginalTable
INSERT INTO #OriginalTable SELECT * FROM #TemNewTable
DROP TABLE #TemNewTable
1赞 Ankit Jindal 8/6/2020 #38

对于表结构

我的桌子

RowID int not null identity(1,1) primary key,
Col1 varchar(20) not null,
Col2 varchar(2048) not null,
Col3 tinyint not null

删除重复项的查询:

DELETE t1
FROM MyTable t1
INNER JOIN MyTable t2
WHERE t1.RowID > t2.RowID
  AND t1.Col1 = t2.Col1
  AND t1.Col2=t2.Col2
  AND t1.Col3=t2.Col3;

我假设这是一种自动递增,其余列具有重复值。RowID

0赞 Mansour Alnasser 3/6/2021 #39

基于两列删除重复项的其他方法

我发现这个查询更容易阅读和替换。

DELETE 
FROM 
 TABLE_NAME 
 WHERE FIRST_COLUMNS 
 IN( 
       SELECT * FROM 
           ( SELECT MIN(FIRST_COLUMNS) 
             FROM TABLE_NAME 
             GROUP BY 
                      FIRST_COLUMNS,
                      SECOND_COLUMNS 
             HAVING COUNT(FIRST_COLUMNS) > 1 
            ) temp 
   )

注意:最好在运行它之前。simulate query

在此处输入图像描述

-1赞 Chandan Kumar Singh 5/1/2021 #40

在postgresql中删除表的重复行的非常简单的方法。

DELETE FROM table1 a
USING table1 b
WHERE a.id < b.id
AND a.column1 = b.column1
AND a.column2 = b.column2;
0赞 Md. Tarikul Islam Soikot 9/19/2021 #41

首先,您可以使用 MIN() 和 Group By 选择最小 RowId。我们将保留这些行。

   SELECT MIN(RowId) as RowId
   FROM MyTable 
   GROUP BY Col1, Col2, Col3

并删除 RowId 的那些不在选定的最小 RowId 中使用

DELETE FROM MyTable WHERE RowId Not IN()

最终查询:

DELETE FROM MyTable WHERE RowId Not IN(

    SELECT MIN(RowId) as RowId
    FROM MyTable 
    GROUP BY Col1, Col2, Col3
)

您也可以在 SQL Fiddle 中查看我的答案

-1赞 Vikas kumar 6/17/2022 #42

删除重复记录

在这种情况下,大于运算符删除除第一条记录之外的所有记录

从用户中删除 u1 u1 加入用户 u2 在哪里 u1.id > u2.id 和 u1.email=u2.email

< 小于运算符,在这种情况下,删除除最后一条记录之外的所有记录

从用户中删除 u1 u1 加入用户 u2 在哪里 u1.id < u2.id 和 u1.email=u2.email

-1赞 michael satumba 10/8/2022 #43

创建另一个将包含原始值的表:

CREATE TABLE table2 AS SELECT *, COUNT(*) FROM table1 GROUP BY name HAVING COUNT (*) > 0