MySQL에서 중복 값 찾기


769

varchar 열이있는 테이블이 있으며이 열에 중복 값이있는 모든 레코드를 찾고 싶습니다. 중복을 찾기 위해 사용할 수있는 가장 좋은 쿼리는 무엇입니까?


1
모든 레코드 찾기를 언급 했으므로 해당 varchar 열의 중복 키와 KEYS를 알아야한다고 가정합니다.
TechTravelThink

값을 얻은 후 키를 충분히 쉽게 찾을 수 있습니다. 모든 중복 값 목록을 원합니다.
Jon Tackabury

답변:


1521

를 수행 SELECT로모그래퍼 GROUP BY절. name 이 중복을 찾으려는 열 이라고 가정 해 봅시다 .

SELECT name, COUNT(*) c FROM table GROUP BY name HAVING c > 1;

첫 번째 열에 이름 값 이있는 결과와 두 번째 값에 해당 값이 몇 번 나타나는지를 반환합니다 .


27
그러나 값이 중복 된 행의 ID를 얻을 수없는 경우 어떻게 유용합니까? 예, 각 중복 값에 대해 새 쿼리 일치를 수행 할 수 있지만 중복을 간단히 나열 할 수 있습니까?
NobleUplift

23
@NobleUplift 당신은 할 수 있으며 GROUP_CONCAT(id)ID를 나열합니다. 예를 들어 내 대답을 참조하십시오.
매트 라돈

5
그것이 말하면 무엇을 의미 ERROR: column "c" does not exist LINE 1할까요?
사용자

15
왜 이것이 받아 들여지는 대답인지, 왜 그렇게 많은 공감대가 있는지 혼란 스럽습니다. OP는 "이 열에 중복 값이있는 모든 레코드를 찾고 싶습니다." 이 답변은 카운트 테이블을 반환합니다. -1
Monica Heddneck

4
HAVING의 작동 방식을 이해하지 못하는 사람들에게는 단순히 결과 집합에 대한 필터 일 뿐이므로 기본 쿼리 이후에 발생합니다.
John Hunt

236
SELECT varchar_col
FROM table
GROUP BY varchar_col
HAVING COUNT(*) > 1;

10
추가 열을 추가하지 않으므로 @levik의 답변보다 우수합니다. IN()/ 와 함께 사용하기에 유용합니다 NOT IN().
wmassingham

172
SELECT  *
FROM    mytable mto
WHERE   EXISTS
        (
        SELECT  1
        FROM    mytable mti
        WHERE   mti.varchar_column = mto.varchar_column
        LIMIT 1, 1
        )

이 쿼리는 distinct뿐만 아니라 완전한 레코드를 반환합니다 varchar_column.

이 검색어는을 사용하지 않습니다 COUNT(*). 중복이 많고 COUNT(*)비싸고 전체가 필요하지 않은 COUNT(*)경우 동일한 값을 가진 두 개의 행이 있는지 알아야합니다.

varchar_column물론 인덱스를 사용 하면이 쿼리 속도가 크게 향상됩니다.


3
아주 좋아요 ORDER BY varchar_column DESC쿼리 끝에 추가 했습니다.
trante

8
이것은 허용 해답이 될뿐만해야 GROUP BY하고 HAVING가능한 중복의 한으로 돌아갑니다. 또한 대신 색인 필드를 사용한 성능 COUNT(*)ORDER BY중복 레코드를 그룹화 할 수 있습니다.
Rémi Breton

1
위 주석에서 언급 한 것처럼이 쿼리를 사용하면 중복 된 모든 행을 나열 할 수 있습니다. 매우 유용한.
TryHarder

4
이것을 보면 어떻게 작동하는지 이해할 수 없습니다. 외부 테이블의 모든 행이 내부 테이블에서도 사용 가능하므로 모든 행이 항상 자체적으로 일치하기 때문에 내부 조건이 항상 참입니까? 쿼리를 시도하고 의심되는 결과를 얻었습니다. 모든 행이 반환되었습니다. 그러나 너무 많은 투표자들과 함께 나는 자신을 의심하고 있습니다. 내부 쿼리에 "AND mto.id <> mti.id"와 같은 것이 누락되지 않았습니까? 내가 추가하면 그것은 나를 위해 작동합니다.
Clox

2
@Quassnoi 좋아. sqlfiddle에 넣으려고했지만 스키마를 만드는 것 외에도 실행하려고하는 모든 쿼리가 시간 초과되어 포기했습니다. "EXISTS"만 제거하면 쿼리가 올바르게 작동한다는 것을 알았습니다.
Clox

144

GROUP_CONCAT서버가 지원 하는 경우 중복 행의 ID를 얻기 위해 levik의 답변을 토대로 쉼표로 구분 된 ID 목록을 반환합니다.

SELECT GROUP_CONCAT(id), name, COUNT(*) c FROM documents GROUP BY name HAVING c > 1;

12
이번에는 GROUP_CONCAT ()에 대해 전혀 몰랐습니다! 매우 유용합니다.
aesede

정말 고마워요. 이것은 정말 도움이됩니다! phpmyadmin에서 업데이트를 시도하는 사람들의 경우 id를 다음과 같은 함수와 함께두면 SELECT id, GROUP_CONCAT(id), name, COUNT(*) c [...]인라인 편집이 가능하고 관련된 모든 행 (또는 적어도 첫 번째 행과 일치)을 업데이트해야하지만 불행히도 편집시 Javascript 오류가 발생합니다. ..
Armfoot

그러면 중복되는 ID 수를 어떻게 계산합니까?
CMCDragonkai

2
모든 ID를 그룹화하지 않고 처음부터 끝까지 어떻게 나열합니까? 옆의 열에 각각의 값이 모두 있습니까? 따라서 그룹화하는 대신 ID 1 및 해당 값, ID 2 및 해당 값만 표시합니다. ID 값이 동일한 경우에도 마찬가지입니다.
MailBlade

1
매우 유용한 답변입니다. 더 많은 사람들이 볼 수 있도록 최상위에 있어야합니다. 나는 그러한 목록을 만들면서 얼마나 많은 고통을 겪었는지 기억하며, 그것은 항상 명령으로 사용할 수있었습니다.
John

13

테이블 이름이 TableABC이고 원하는 열이 Col이고 T1의 기본 키가 Key라고 가정합니다.

SELECT a.Key, b.Key, a.Col 
FROM TableABC a, TableABC b
WHERE a.Col = b.Col 
AND a.Key <> b.Key

위의 답변에 비해이 방법의 장점은 키를 제공한다는 것입니다.


4
+1 편리하기 때문입니다. 아이러니하게도 결과 자체에는 중복 항목이 포함되지만 (a 및 b, b 및 a를 나열)
Fabien Snauwaert

2
@FabienSnauwaert보다 작거나보다 큰 비교를 통해 일부 복제본을 제거 할 수 있습니다.
Michael

@TechTravel 귀하의 대답은 매우 분명합니다.하지만 그 덕분에 큰 테이블에는 시간이 더 걸리고 (20,000 개 이상의 항목 테이블에서 약 2mn) 25 개의 첫 결과를 표시 한 후 다음을 표시하려면 phpmyadmin show error "# 1052-order 절의 'id'열이 모호합니다. "
bcag2

12
SELECT * 
FROM `dps` 
WHERE pid IN (SELECT pid FROM `dps` GROUP BY pid HAVING COUNT(pid)>1)

1
아니, 이것은 아마도 가장 느리기 때문입니다. 부속 선택은 리턴 된 모든 행에 대해 실행되므로 악명 높게 느립니다.
Oddman

10

Employee의 이름 열에 중복 된 레코드 수를 찾으려면 아래 쿼리가 도움이됩니다.

Select name from employee group by name having count(*)>1;

10

중복이 포함 된 모든 데이터를 얻으려면 이것을 사용했습니다.

SELECT * FROM TableName INNER JOIN(
  SELECT DupliactedData FROM TableName GROUP BY DupliactedData HAVING COUNT(DupliactedData) > 1 order by DupliactedData)
  temp ON TableName.DupliactedData = temp.DupliactedData;

TableName = 작업중인 테이블입니다.

DupliactedData = 찾고있는 중복 데이터


이것은 각각의 사본을 자체 행에 표시합니다. 그것이 내가 필요한 것입니다. 감사.
warmwhisky

8

내 마지막 쿼리에는 group by, count & GROUP_CONCAT를 결합하는 데 도움이되는 몇 가지 답변이 포함되어 있습니다.

SELECT GROUP_CONCAT(id), `magento_simple`, COUNT(*) c 
FROM product_variant 
GROUP BY `magento_simple` HAVING c > 1;

이것은 두 예제 (쉼표로 구분), 필요한 바코드 및 중복 수의 ID를 제공합니다.

테이블과 열을 적절히 변경하십시오.


8

중복 측면에서 많은 용도로 사용되는 JOIN 방식이 표시되지 않습니다.

이 방법은 실제 두 배의 결과를 제공합니다.

SELECT t1.* FROM my_table as t1 
LEFT JOIN my_table as t2 
ON t1.name=t2.name and t1.id!=t2.id 
WHERE t2.id IS NOT NULL 
ORDER BY t1.name

2
참고-중복 레코드가 두 개 이상 존재할 가능성이있는 경우 '특별한 somecol ..'을 선택해야합니다. 그렇지 않으면 결과에 찾은 중복 행의 중복이 결과에 포함됩니다.
Drew

7
SELECT t.*,(select count(*) from city as tt
  where tt.name=t.name) as count
  FROM `city` as t
  where (
     select count(*) from city as tt
     where tt.name=t.name
  ) > 1 order by count desc

도시 를 테이블로 바꿉니다 . 교체 이름을 당신의 필드 이름으로



6

위의 결과를 보았고 중복 된 단일 열 값을 확인 해야하는 경우 쿼리가 제대로 작동합니다. 예를 들어 이메일.

그러나 더 많은 열을 확인해야하고 결과 조합을 확인하려면이 쿼리가 제대로 작동합니다.

SELECT COUNT(CONCAT(name,email)) AS tot,
       name,
       email
FROM users
GROUP BY CONCAT(name,email)
HAVING tot>1 (This query will SHOW the USER list which ARE greater THAN 1
              AND also COUNT)

정확히 무엇이 필요했습니다! 다음은 3 개의 필드에서 중복 항목을 확인하는 쿼리입니다.SELECT COUNT(CONCAT(userid,event,datetime)) AS total, userid, event, datetime FROM mytable GROUP BY CONCAT(userid, event, datetime ) HAVING total>1
Kai Noack

4

전체 행을 볼 수 있기 때문에 창 함수 (MySQL 8.0 이상)를 사용하여 중복 항목을 찾는 것이 좋습니다.

WITH cte AS (
  SELECT *
    ,COUNT(*) OVER(PARTITION BY col_name) AS num_of_duplicates_group
    ,ROW_NUMBER() OVER(PARTITION BY col_name ORDER BY col_name2) AS pos_in_group
  FROM table
)
SELECT *
FROM cte
WHERE num_of_duplicates_group > 1;

DB 피들 데모


3
SELECT 
    t.*,
    (SELECT COUNT(*) FROM city AS tt WHERE tt.name=t.name) AS count 
FROM `city` AS t 
WHERE 
    (SELECT count(*) FROM city AS tt WHERE tt.name=t.name) > 1 ORDER BY count DESC

1
동일한 하위 쿼리를 두 번 수행하는 것은 비효율적입니다.
NobleUplift


3
CREATE TABLE tbl_master
    (`id` int, `email` varchar(15));

INSERT INTO tbl_master
    (`id`, `email`) VALUES
    (1, 'test1@gmail.com'),
    (2, 'test2@gmail.com'),
    (3, 'test1@gmail.com'),
    (4, 'test2@gmail.com'),
    (5, 'test5@gmail.com');

QUERY : SELECT id, email FROM tbl_master
WHERE email IN (SELECT email FROM tbl_master GROUP BY email HAVING COUNT(id) > 1)

2
SELECT DISTINCT a.email FROM `users` a LEFT JOIN `users` b ON a.email = b.email WHERE a.id != b.id;

1
쿼리하는 열이 색인화되지 않으면 이것이 느리거나 완료되지 않을 수도 있습니다. 그렇지 않으면 중복 된 행의 모든 ​​ID 로 변경 a.email하여 a.*가져올 수있었습니다 .
NobleUplift

@NobleUplift 무슨 소리 야?
Michael

@Michael 이것은 3 살이 기 때문에 사용중인 MySQL의 버전에 대해 테스트 할 수 없지만 선택한 열에 인덱스가없는 데이터베이스에서 동일한 쿼리를 시도 했으므로 꽤 오래 걸렸습니다. 몇 초만에 끝납니다. SELECT DISTINCT a.*거의 즉시 해결 되도록 변경했습니다 .
NobleUplift

@NobleUplift 아 알았어. 나는 그것이 느리다는 것을 이해할 수있다 ... 내가 염려하는 부분은 "마무리하지 않을 수도있다"는 것이다.
Michael

@Michael 나는 우리 시스템에서 어떤 테이블을이 쿼리를 실행했는지 기억하지 못하지만 수백만 개의 레코드가있는 테이블의 경우 아마 완료되었을 것입니다. 그러나 시간이 너무 오래 걸리면 실제로 끝날 것입니다.
NobleUplift

1

여러 개의 필드가있는 중복 행을 제거하려면 먼저 고유 한 행에만 지정된 새 고유 키에 해당 행을 할당 한 다음 "group by"명령을 사용하여 동일한 새 고유 키로 중복 행을 제거하십시오.

Create TEMPORARY table tmp select concat(f1,f2) as cfs,t1.* from mytable as t1;
Create index x_tmp_cfs on tmp(cfs);
Create table unduptable select f1,f2,... from tmp group by cfs;

설명을 추가 할 수 있습니까?
Robert

왜 사용하지 CREATE TEMPORARY TABLE ...않습니까? 솔루션에 대한 약간의 설명이 좋을 것입니다.
maxhb

1

매우 늦게 기여한 것 중 하나입니다. 누구나 도움이 될 경우를 대비해서 ... 은행 거래 앱에서 일치하는 거래 쌍 (실제로 계좌 대 계좌 이체)을 찾아서 어떤 거래인지 식별하는 작업이있었습니다. 계정 간 이체 거래마다 '보낸 사람'과 '받는 사람'이되었으므로 결과는 다음과 같습니다.

SELECT 
    LEAST(primaryid, secondaryid) AS transactionid1,
    GREATEST(primaryid, secondaryid) AS transactionid2
FROM (
    SELECT table1.transactionid AS primaryid, 
        table2.transactionid AS secondaryid
    FROM financial_transactions table1
    INNER JOIN financial_transactions table2 
    ON table1.accountid = table2.accountid
    AND table1.transactionid <> table2.transactionid 
    AND table1.transactiondate = table2.transactiondate
    AND table1.sourceref = table2.destinationref
    AND table1.amount = (0 - table2.amount)
) AS DuplicateResultsTable
GROUP BY transactionid1
ORDER BY transactionid1;

결과는 DuplicateResultsTable일치하는 (즉, 중복 된) 트랜잭션을 포함하는 행을 제공하지만 동일한 쌍과 일치 할 때 두 번째로 동일한 트랜잭션 ID를 반대로 제공하므로 외부 SELECT는 첫 번째 트랜잭션 ID별로 그룹화됩니다. 사용하여 LEASTGREATEST확인이 개는 TransactionId의 정보는 다음의 제품에 안전하게 만드는 결과 같은 순서에 항상 있도록 GROUP따라서 모든 중복 일치를 제거, 최초의 하나. 거의 백만 건의 기록을 뚫고 2 초 이내에 12,000 건 이상의 경기를 확인했습니다. 물론 transactionid는 기본 인덱스이며 실제로 도움이되었습니다.


1
Select column_name, column_name1,column_name2, count(1) as temp from table_name group by column_name having temp > 1

1
SELECT ColumnA, COUNT( * )
FROM Table
GROUP BY ColumnA
HAVING COUNT( * ) > 1

3
고유 한 항목도 발견하므로 올바르지 않습니다. 0은 1이어야합니다.
Kafoso

1

중복 사용을 제거하려면 DISTINCT

그렇지 않으면이 쿼리를 사용하십시오.

SELECT users.*,COUNT(user_ID) as user FROM users GROUP BY user_name HAVING user > 1;


0

이 쿼리를 사용해보십시오.

SELECT name, COUNT(*) value_count FROM company_master GROUP BY name HAVING value_count > 1;
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.