SQL 테이블에서 중복 값 찾기


1934

하나의 필드로 중복 항목을 쉽게 찾을 수 있습니다.

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

3
nameSELECT 의 필드로 인해 MSSQL 서버에서는 작동하지 않습니다 .
E. van Putten

내가 필요한 것은 이메일이 중복 된 레코드의 ID입니다
Marcos Di Paolo

답변:


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

두 열을 모두 그룹화하면됩니다.

참고 : 이전 ANSI 표준은 GROUP BY에 모든 집계되지 않은 열을 갖지만 "기능 종속성" 이라는 개념으로 변경되었습니다 .

관계형 데이터베이스 이론에서 기능적 종속성은 데이터베이스와의 관계에서 두 속성 세트 간의 제약 조건입니다. 다시 말해서 기능적 종속성은 관계에서 속성 간의 관계를 설명하는 제한 조건입니다.

지원이 일관되지 않습니다 :


92
@webXL WHERE는 단일 레코드와 함께 작동 HAVING은 그룹과 함께 작동
bjan

8
@gbn 결과에 ID를 포함시킬 수 있습니까? 그런 다음 나중에 중복을 삭제하는 것이 더 쉬울 것입니다.
user797717

13
@ user797717 : MIN (ID)이 있어야하고 MIN (ID) 값이 아닌 경우 마지막에없는 ID 값을 삭제해야합니다
gbn

1
열에 null 값이있는 경우는 어떻습니까?
Ankit Dhingra

1
정말 고마워요. 그래도 오라클에서 작동하지만 조건보다는 고유성이 필요했습니다.>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)

dups의 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
)

IMHO를 읽고 이해하기가 훨씬 쉬움

참고 : 유일한 문제는 삭제 된 행이 없을 때까지 요청을 실행해야한다는 것입니다.


2
좋고 읽기 쉬운; 그래도 여러 개의 중복 행을 한 번에 삭제하는 방법을 찾고 싶습니다.
Dickon Reed

1
내가 얻을 이것은 나를 위해 작동하지 않습니다You can't specify target table 'users' for update in FROM clause
Whitecat

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 line 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을 사용한 적이 나는 깜짝 놀라게 할 중단 적이 얼마나 많은 SQL에서 같은 일을 할 수있는 방법.!
조 루더


28

파티에 조금 늦었지만 모든 중복 ID를 찾는 정말 멋진 해결책을 찾았습니다.

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

2
구문상의 설탕 작업으로 나타납니다. 좋은 발견.
Chef_Code

3
명심 GROUP_CONCAT당신은 모든 얻지 못할 수도 있으므로, 일부 소정의 길이 후 중지됩니다 id들.
v010dya

24

이 코드를 사용해보십시오

WITH CTE AS

( SELECT Id, Name, Age, Comments, RN = ROW_NUMBER()OVER(PARTITION BY Name,Age ORDER BY ccn)
FROM ccnmaster )
select * from CTE 

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
테이블 '도시'나 업데이트 절이 없습니다. 무슨 소리 야? 삭제 쿼리에서 오류는 어디에 있습니까?
Martin Silovský

2
이것이 OP의 데이터와 어떻게 작동합니까?
thoroc 2019

3
"OP"는 무엇을 의미합니까?
Martin Silovský

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
스택 오버플로에서 코드 만 답변이 찌그러집니다. 왜 이것이 질문에 대답하는지 설명 할 수 있습니까?
Rich Benner

2
@ RichBenner : 결과에서 각각의 모든 행과 같은 응답을 찾지 못했으며 모두 중복 된 행과 한 눈에 보이지 않는 그룹 및 그룹화하지 않는 그룹을 알려줍니다. by 다른 쿼리 그룹과의 쿼리는 좋은 옵션이 아닙니다.
Narendra

2
select 문에 Id를 추가하고 duplicated에서 필터링하면 중복 된 ID를 삭제하고 각 ID를 유지할 수 있습니다.
Antoine Reinhold Bertrand

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
질문에 따라 어떻게 작동합니까? 여러 열의 정보를 복제하는 행 (예 : "이메일"및 "이름")은 다른 행에 제공 되지 않습니다 .
Jeroen

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
이것은 최상위 답변 에 아무것도 추가 하지 않으며 기술적으로 질문에 게시 된 코드와 실제로 다르지 않습니다.
Jeroen

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/


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

전체 테이블을 참조하지 않으면을 사용 COUNT하지 않고 사용할 수 없습니다 GROUP BY.
RalfFriedl

Group By없이 COUNT를 사용했지만 여기에 COUNT를 쓰려고 잘못 입력했습니다
Mohammad Neamul Islam

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

여기서 우리는 orignal 테이블의 모든 고유 레코드를 가져 와서 원래 테이블의 레코드를 삭제했습니다. 다시 새 테이블의 모든 고유 값을 원래 테이블에 삽입 한 다음 새 테이블을 삭제했습니다.


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
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.