在SQL表中查找重复值


1931

查找一个字段的重复项很容易:

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

所以如果我们有一张桌子

ID   NAME   EMAIL
1    John   asd@asd.com
2    Sam    asd@asd.com
3    Tom    asd@asd.com
4    Bob    bob@asd.com
5    Tom    asd@asd.com

该查询将为我们提供John,Sam,Tom,Tom,因为它们都相同email

不过,我想是让具有相同重复email name

也就是说,我想获得“ Tom”,“ Tom”。

我需要这个的原因:我犯了一个错误,并允许插入重复项nameemail值。现在,我需要删除/更改重复项,因此我需要先找到它们。


28
我认为这不会让您在第一个示例中选择名称,因为它不在聚合函数中。“匹配的电子邮件地址及其名称的计数是多少”是一些棘手的逻辑……
sXe 2013年

3
发现由于nameSELECT 中的字段,此方法不适用于MSSQL Server 。
E. van Putten

我需要的是重复电子邮件的记录ID
Marcos Di Paolo

Answers:


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

只需将两个列都分组即可。

注意:较早的ANSI标准将在GROUP BY中具有所有非聚合的列,但是随着“功能依赖”的思想而改变了:

在关系数据库理论中,功能依赖性是数据库中某个关系中两组属性之间的约束。换句话说,功能依赖性是描述关系中属性之间关系的约束。

支持不一致:


92
@webXL WHERE与单个记录一起工作HAVING与组一起工作
2013年1

8
@gbn是否可以在结果中包含ID?然后,以后删除这些重复项会更容易。
user797717 2014年

13
@ user797717:您需要先拥有MIN(ID),然后再删除MIN(ID)值不在最后的ID值
gbn 2014年

1
如果任何列具有空值,情况如何?
Ankit Dhingra

1
非常感谢,是的,它确实适用于Oracle,尽管我需要条件的唯一性,而不是>1 =1
Bill Naylor

370

尝试这个:

declare @YourTable table (id int, name varchar(10), email varchar(50))

INSERT @YourTable VALUES (1,'John','John-email')
INSERT @YourTable VALUES (2,'John','John-email')
INSERT @YourTable VALUES (3,'fred','John-email')
INSERT @YourTable VALUES (4,'fred','fred-email')
INSERT @YourTable VALUES (5,'sam','sam-email')
INSERT @YourTable VALUES (6,'sam','sam-email')

SELECT
    name,email, COUNT(*) AS CountOf
    FROM @YourTable
    GROUP BY name,email
    HAVING COUNT(*)>1

输出:

name       email       CountOf
---------- ----------- -----------
John       John-email  2
sam        sam-email   2

(2 row(s) affected)

如果您想让公仔的ID使用此:

SELECT
    y.id,y.name,y.email
    FROM @YourTable y
        INNER JOIN (SELECT
                        name,email, COUNT(*) AS CountOf
                        FROM @YourTable
                        GROUP BY name,email
                        HAVING COUNT(*)>1
                    ) dt ON y.name=dt.name AND y.email=dt.email

输出:

id          name       email
----------- ---------- ------------
1           John       John-email
2           John       John-email
5           sam        sam-email
6           sam        sam-email

(4 row(s) affected)

删除重复项尝试:

DELETE d
    FROM @YourTable d
        INNER JOIN (SELECT
                        y.id,y.name,y.email,ROW_NUMBER() OVER(PARTITION BY y.name,y.email ORDER BY y.name,y.email,y.id) AS RowRank
                        FROM @YourTable y
                            INNER JOIN (SELECT
                                            name,email, COUNT(*) AS CountOf
                                            FROM @YourTable
                                            GROUP BY name,email
                                            HAVING COUNT(*)>1
                                        ) dt ON y.name=dt.name AND y.email=dt.email
                   ) dt2 ON d.id=dt2.id
        WHERE dt2.RowRank!=1
SELECT * FROM @YourTable

输出:

id          name       email
----------- ---------- --------------
1           John       John-email
3           fred       John-email
4           fred       fred-email
5           sam        sam-email

(4 row(s) affected)


72

如果要删除重复项,这是比在三重子选择中查找偶数/奇数行更简单的方法:

SELECT id, name, email 
FROM users u, users u2
WHERE u.name = u2.name AND u.email = u2.email AND u.id > u2.id

如此删除:

DELETE FROM users
WHERE id IN (
    SELECT id/*, name, email*/
    FROM users u, users u2
    WHERE u.name = u2.name AND u.email = u2.email AND u.id > u2.id
)

更加容易阅读和理解恕我直言

注意:唯一的问题是您必须执行请求,直到没有删除的行为止,因为每次都只删除每个重复项中的1个


2
美观且易于阅读;我想找到一种一次性删除多个重复行的方法。
Dickon Reed

1
当我得到时,这对我不起作用You can't specify target table 'users' for update in FROM clause
Whitecat '17

1
@Whitecat似乎是一个简单的MySQL问题:stackoverflow.com/questions/4429319/…–
AncAinu

1
对我失败。我得到:“ DBD :: CSV :: st执行失败:在/Users/hornenj/perl5/perlbrew/perls/perl-5.26.0/lib/site_perl/5.26的哈希元素中使用未初始化的值$ _ [1]。 0 / SQL / Eval.pm第43行“
Nigel Horne,

1
我认为where子句应该是“ u.name = u2.name AND u.email = u2.email AND(u.id> u2.id OR u2.id> u.id)”吗?
GiveEmTheBoot

48

尝试以下方法:

SELECT * FROM
(
    SELECT Id, Name, Age, Comments, Row_Number() OVER(PARTITION BY Name, Age ORDER By Name)
        AS Rank 
        FROM Customers
) AS B WHERE Rank>1

3
对SELECT *的微小更改帮助我解决了一个小时的搜索问题。我以前从未使用过OVER(PARTITION BY。对于使用SQL执行相同操作的方式有很多,我永远不会感到惊讶!
Joe Ruder

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

28

聚会晚了一点,但是我发现了一个非常酷的解决方法来查找所有重复的ID:

SELECT GROUP_CONCAT( id )
FROM users
GROUP BY email
HAVING ( COUNT(email) > 1 )

2
似乎是一种语法糖解决方案。好发现。
Chef_Code

3
请记住,这GROUP_CONCAT将在预定的长度后停止,因此您可能无法获得所有的ids。
v010dya


23

这将从每组重复项中选择/删除所有重复记录,但一条记录除外。因此,删除将保留所有唯一记录+每组重复项中的一条记录。

选择重复项:

SELECT *
FROM table
WHERE
    id NOT IN (
        SELECT MIN(id)
        FROM table
        GROUP BY column1, column2
);

删除重复项:

DELETE FROM table
WHERE
    id NOT IN (
        SELECT MIN(id)
        FROM table
        GROUP BY column1, column2
);

注意大量的记录,这可能会导致性能问题。


2
删除查询中的错误-您无法在FROM子句中指定要更新的目标表“城市”
Ali Azhar,

2
没有表'city'或update子句。你什么意思?删除查询中的错误在哪里?
MartinSilovský18年

2
OP如何处理其数据?
thoroc

3
“ OP”是什么意思?
马丁·西洛夫斯基(MartinSilovský)

19

如果您使用Oracle,则最好采用以下方式:

create table my_users(id number, name varchar2(100), email varchar2(100));

insert into my_users values (1, 'John', 'asd@asd.com');
insert into my_users values (2, 'Sam', 'asd@asd.com');
insert into my_users values (3, 'Tom', 'asd@asd.com');
insert into my_users values (4, 'Bob', 'bob@asd.com');
insert into my_users values (5, 'Tom', 'asd@asd.com');

commit;

select *
  from my_users
 where rowid not in (select min(rowid) from my_users group by name, email);

15
select name, email
, case 
when ROW_NUMBER () over (partition by name, email order by name) > 1 then 'Yes'
else 'No'
end "duplicated ?"
from users

2
只有代码答案在Stack Overflow上不被接受,您能否解释为什么这会回答问题?
Rich Benner

2
@RichBenner:我没有找到结果中的每一行,它告诉我们哪些都是重复的行,哪些不是一目了然的,不要归类,因为如果我们想将其合并与任何其他查询分组依据一起查询不是一个好的选择。
纳伦德拉

2
在选择语句中添加ID并过滤重复的ID,这使您可以删除重复的ID并保留每个ID。
安托万·莱因霍尔德·贝特朗

12

如果希望查看表中是否有重复的行,可以在查询下面使用:

create table my_table(id int, name varchar(100), email varchar(100));

insert into my_table values (1, 'shekh', 'shekh@rms.com');
insert into my_table values (1, 'shekh', 'shekh@rms.com');
insert into my_table values (2, 'Aman', 'aman@rms.com');
insert into my_table values (3, 'Tom', 'tom@rms.com');
insert into my_table values (4, 'Raj', 'raj@rms.com');


Select COUNT(1) As Total_Rows from my_table 
Select Count(1) As Distinct_Rows from ( Select Distinct * from my_table) abc 

11

这是我想到的一件容易的事。它使用公用表表达式(CTE)和分区窗口(我认为这些功能在SQL 2008和更高版本中)。

本示例查找具有重复名称和dob的所有学生。您要检查重复项的字段位于OVER子句中。您可以在投影中包括任何其他想要的字段。

with cte (StudentId, Fname, LName, DOB, RowCnt)
as (
SELECT StudentId, FirstName, LastName, DateOfBirth as DOB, SUM(1) OVER (Partition By FirstName, LastName, DateOfBirth) as RowCnt
FROM tblStudent
)
SELECT * from CTE where RowCnt > 1
ORDER BY DOB, LName


10

我们如何计算重复值?重复2次或大于2次。只计算它们,而不是按组计算。

select COUNT(distinct col_01) from Table_01

2
对于所提出的问题,这将如何工作?这并没有让行,在多个列中的重复信息不同行(例如,“电子邮件”和“名”)。
耶隆2015年

10

通过使用CTE,我们也可以找到类似的重复值

with MyCTE
as
(
select Name,EmailId,ROW_NUMBER() over(PARTITION BY EmailId order by id) as Duplicate from [Employees]

)
select * from MyCTE where Duplicate>1

9
 select emp.ename, emp.empno, dept.loc 
          from emp
 inner join dept 
          on dept.deptno=emp.deptno
 inner join
    (select ename, count(*) from
    emp
    group by ename, deptno
    having count(*) > 1)
 t on emp.ename=t.ename order by emp.ename
/

7

SELECT id, COUNT(id) FROM table1 GROUP BY id HAVING COUNT(id)>1;

我认为这将可以正常搜索特定列中的重复值。


6
这并没有为最高答案添加任何内容,并且从技术上讲,它与问题中发布的OP的代码甚至没有真正的不同。
耶隆2015年

7
SELECT * FROM users u where rowid = (select max(rowid) from users u1 where
u.email=u1.email);

6

这也应该起作用,也许可以尝试一下。

  Select * from Users a
            where EXISTS (Select * from Users b 
                where (     a.name = b.name 
                        OR  a.email = b.email)
                     and a.ID != b.id)

如果您搜索的是具有某种前缀或一般更改的重复项,例如邮件中的新域,则特别好。那么您可以在这些列上使用replace()


5

如果要查找重复数据(通过一个或多个条件)并选择实际行。

with MYCTE as (
    SELECT DuplicateKey1
        ,DuplicateKey2 --optional
        ,count(*) X
    FROM MyTable
    group by DuplicateKey1, DuplicateKey2
    having count(*) > 1
) 
SELECT E.*
FROM MyTable E
JOIN MYCTE cte
ON E.DuplicateKey1=cte.DuplicateKey1
    AND E.DuplicateKey2=cte.DuplicateKey2
ORDER BY E.DuplicateKey1, E.DuplicateKey2, CreatedAt

http://developer.azurewebsites.net/2014/09/better-sql-group-by-find-duplicate-data/



3

删除名称重复的记录

;WITH CTE AS    
(

    SELECT ROW_NUMBER() OVER (PARTITION BY name ORDER BY name) AS T FROM     @YourTable    
)

DELETE FROM CTE WHERE T > 1

3

从表中的重复记录中检查。

select * from users s 
where rowid < any 
(select rowid from users k where s.name = k.name and s.email = k.email);

要么

select * from users s 
where rowid not in 
(select max(rowid) from users k where s.name = k.name and s.email = k.email);

删除表中的重复记录。

delete from users s 
where rowid < any 
(select rowid from users k where s.name = k.name and s.email = k.email);

要么

delete from users s 
where rowid not in 
(select max(rowid) from users k where s.name = k.name and s.email = k.email);


1

我们可以在这里使用具有聚合功能的功能,如下所示

create table #TableB (id_account int, data int, [date] date)
insert into #TableB values (1 ,-50, '10/20/2018'),
(1, 20, '10/09/2018'),
(2 ,-900, '10/01/2018'),
(1 ,20, '09/25/2018'),
(1 ,-100, '08/01/2018')  

SELECT id_account , data, COUNT(*)
FROM #TableB
GROUP BY id_account , data
HAVING COUNT(id_account) > 1

drop table #TableB

这里,id_account和data这两个字段与Count(*)一起使用。因此,它将为所有记录提供两列中相同值超过一倍的记录。

我们由于某些原因错误地错过了在SQL Server表中添加任何约束的条件,并且该记录已在前端应用程序的所有列中重复插入。然后我们可以使用下面的查询从表中删除重复的查询。

SELECT DISTINCT * INTO #TemNewTable FROM #OriginalTable
TRUNCATE TABLE #OriginalTable
INSERT INTO #OriginalTable SELECT * FROM #TemNewTable
DROP TABLE #TemNewTable

在这里,我们已获取原始表的所有不同记录,并删除了原始表的记录。同样,我们将所有新表中的不同值插入到原始表中,然后删除新表。


1

您可能想尝试一下

SELECT NAME, EMAIL, COUNT(*)
FROM USERS
GROUP BY 1,2
HAVING COUNT(*) > 1

1

这里最重要的是拥有最快的功能。还应确定重复的索引。自联接是一个不错的选择,但要具有更快的功能,最好先查找具有重复项的行,然后与原始表联接以查找重复行的ID。最后,按ID以外的任何列排序,以使彼此之间有重复的行。

SELECT u.*
FROM users AS u
JOIN (SELECT username, email
      FROM users
      GROUP BY username, email
      HAVING COUNT(*)>1) AS w
ON u.username=w.username AND u.email=w.email
ORDER BY u.email;

0

您可以使用SELECT DISTINCT关键字来消除重复项。您还可以按名称过滤,并在表上获取具有该名称的所有人。


0

确切的代码会有所不同,具体取决于您是要查找重复的行还是要查找具有相同电子邮件和名称的不同ID。如果id是主键,或者具有唯一约束,则不存在此区别,但是问题并未指定。在前一种情况下,您可以使用其他几个答案中给出的代码:

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

在后一种情况下,您将使用:

SELECT name, email, COUNT(DISTINCT id)
FROM users
GROUP BY name, email
HAVING COUNT(DISTINCT id) > 1
ORDER BY COUNT(DISTINCT id) DESC
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.