SQL Server에서 중복 행 찾기


231

조직의 SQL Server 데이터베이스가 있으며 중복 행이 많이 있습니다. select 문을 실행하여이 모든 내용과 중복 된 내용을 파악하고 각 조직과 관련된 ID도 반환하려고합니다.

다음과 같은 진술 :

SELECT     orgName, COUNT(*) AS dupes  
FROM         organizations  
GROUP BY orgName  
HAVING      (COUNT(*) > 1)

같은 것을 반환합니다

orgName        | dupes  
ABC Corp       | 7  
Foo Federation | 5  
Widget Company | 2 

그러나 나는 또한 그것들의 ID를 얻고 싶습니다. 이것을 할 수있는 방법이 있습니까? 아마

orgName        | dupeCount | id  
ABC Corp       | 1         | 34  
ABC Corp       | 2         | 5  
...  
Widget Company | 1         | 10  
Widget Company | 2         | 2  

그 이유는 이러한 조직에 연결되는 별도의 사용자 테이블이 있기 때문에 통합하고 싶습니다 (따라서 듀프를 제거하여 사용자가 듀프 조직 대신 동일한 조직에 연결). 그러나 수동으로 부분을 원하므로 아무것도 조이지 않아도 모든 듀프 조직의 ID를 반환하는 진술이 필요하므로 사용자 목록을 살펴볼 수 있습니다.

답변:


313
select o.orgName, oc.dupeCount, o.id
from organizations o
inner join (
    SELECT orgName, COUNT(*) AS dupeCount
    FROM organizations
    GROUP BY orgName
    HAVING COUNT(*) > 1
) oc on o.orgName = oc.orgName

4
예를 들어 레코드 수가 10million plus 더한 경우이 쿼리에 제한이 있습니까?
Steam

3
@Steam 정답 :이 답변은 수백만 개의 레코드가있는 더 큰 데이터베이스에서는 효율적이지 않습니다. Aykut에서 제출 한 GroupBy / Having 답변을 선호하십시오.이 답변은 데이터베이스에 의해 최적화 될 수 있습니다. 한 가지 예외 : Count (*) 대신 Count (0)를 사용하여 작업을 단순화하는 것이 좋습니다.
Mike Christian

1
@Mike-왜 Count (0) 대 Count (*)?
KornMuffin

2
@KornMuffin 회고하면 Count ()에 대한 나의 의견은 무효입니다. Count ()에서 null이 아닌 평가를 사용하면 외부 조인에서 반환 된 null이 아닌 결과를 계산하려는 경우에만 유용합니다. 그렇지 않으면 Count (*)를 사용하십시오. 좋은 설명이 여기에 있습니다 .
Mike Christian

섹션 isnull()에서 Null을 허용하는 열에 사용on
Arif Ulusoy

92

다음 쿼리를 실행하고 max(id)해당 행을 사용 하여 중복 항목을 찾아 삭제할 수 있습니다.

SELECT orgName, COUNT(*), Max(ID) AS dupes 
FROM organizations 
GROUP BY orgName 
HAVING (COUNT(*) > 1)

그러나이 쿼리를 몇 번 실행해야합니다.


정확히 실행해야 MAX( COUNT(*) ) - 1할 수도 있지만 여전히 가능할 수 있습니다.
DerMike

1
hi는 2와 같이 max id 대신 모든 id를 얻는 방법입니다 max와 min을 사용할 수 있지만 2 이상은 어떻습니까? @DerMike
Arijit Mukherjee

31

다음과 같이 할 수 있습니다.

SELECT
    o.id, o.orgName, d.intCount
FROM (
     SELECT orgName, COUNT(*) as intCount
     FROM organizations
     GROUP BY orgName
     HAVING COUNT(*) > 1
) AS d
    INNER JOIN organizations o ON o.orgName = d.orgName

삭제할 수있는 레코드 만 반환하려면 (둘 중 하나를 남겨두고) 다음을 사용할 수 있습니다.

SELECT
    id, orgName
FROM (
     SELECT 
         orgName, id,
         ROW_NUMBER() OVER (PARTITION BY orgName ORDER BY id) AS intRow
     FROM organizations
) AS d
WHERE intRow != 1

편집 : SQL Server 2000에는 ROW_NUMBER () 함수가 없습니다. 대신 다음을 사용할 수 있습니다.

SELECT
    o.id, o.orgName, d.intCount
FROM (
     SELECT orgName, COUNT(*) as intCount, MIN(id) AS minId
     FROM organizations
     GROUP BY orgName
     HAVING COUNT(*) > 1
) AS d
    INNER JOIN organizations o ON o.orgName = d.orgName
WHERE d.minId != o.id

첫 번째 진술은 효과가 있지만 두 번째 진술은 효과가없는 것 같습니다.
xtine

SQL Server가 row_number ()를 인식하지 못하는 것 같습니다.
xtine

아 ... 구 버전의 SQL Server가 있습니까? SQL Server 2005에 도입 된 것 같습니다.
Paul

3
다시 한번 감사드립니다, 내가 이것을 할 필요가있을 때마다 나는 여기에 당신을 사랑합니다
workabyte

9

올바른 것으로 표시된 솔루션은 저에게 효과가 없었지만이 답변은 훌륭하게 작동했습니다 .MySql에서 중복 행 목록 가져 오기

SELECT n1.* 
FROM myTable n1
INNER JOIN myTable n2 
ON n2.repeatedCol = n1.repeatedCol
WHERE n1.id <> n2.id

결과 집합에 많은 속임수가 생겨서 그와 관련된 문제도 해결해야합니다.
Renan

1
ID가 숫자 인 경우 확인 n1.id > n2.id하면 각 쌍이 두 번 표시되지 않습니다.
19 분 59 초에 응시 됨

9

당신은 이것을 시도 할 수 있습니다, 그것은 당신에게 가장 좋습니다

 WITH CTE AS
    (
    SELECT *,RN=ROW_NUMBER() OVER (PARTITION BY orgName ORDER BY orgName DESC) FROM organizations 
    )
    select * from CTE where RN>1
    go

어떤 방법이 쉼표 분할 또는 다른 컬럼에있는 모든 ID를 얻을 수
Arijit 무 케르에게

6

중복을 삭제하려는 경우 :

WITH CTE AS(
   SELECT orgName,id,
       RN = ROW_NUMBER()OVER(PARTITION BY orgName ORDER BY Id)
   FROM organizations
)
DELETE FROM CTE WHERE RN > 1

6
select * from [Employees]

중복 레코드 찾기 1) CTE 사용

with mycte
as
(
select Name,EmailId,ROW_NUMBER() over(partition by Name,EmailId order by id) as Duplicate from [Employees]
)
select * from mycte

2) GroupBy를 사용함으로써

select Name,EmailId,COUNT(name) as Duplicate from  [Employees] group by Name,EmailId 

이것은 10m 행 이상의 데이터를 선택할 때 가장 빠른 솔루션입니다. 감사합니다
Fandango68

4
Select * from (Select orgName,id,
ROW_NUMBER() OVER(Partition By OrgName ORDER by id DESC) Rownum
From organizations )tbl Where Rownum>1

따라서 rowum이 1보다 큰 레코드는 테이블의 중복 레코드가됩니다. 먼저 '분할 기준'을 레코드별로 그룹화 한 후 일련 번호를 지정하여 직렬화하십시오. 따라서 rownum> 1은 삭제 될 수있는 중복 레코드입니다.


내부 select 절에 더 많은 열을 쉽게 추가 할 수 있기 때문에 이것을 좋아합니다. 따라서 '조직'테이블에서 다른 열을 반환하려는 경우 해당 열에 대해 '그룹화'를 수행 할 필요가 없습니다.
Gwasshoppa


2
select a.orgName,b.duplicate, a.id
from organizations a
inner join (
    SELECT orgName, COUNT(*) AS duplicate
    FROM organizations
    GROUP BY orgName
    HAVING COUNT(*) > 1
) b on o.orgName = oc.orgName
group by a.orgName,a.id

1
select orgname, count(*) as dupes, id 
from organizations
where orgname in (
    select orgname
    from organizations
    group by orgname
    having (count(*) > 1)
)
group by orgname, id

1

몇 가지 방법이 있습니다 duplicate rows 있습니다.

내 솔루션의 경우 먼저이 표를 고려하십시오.

CREATE TABLE #Employee
(
ID          INT,
FIRST_NAME  NVARCHAR(100),
LAST_NAME   NVARCHAR(300)
)

INSERT INTO #Employee VALUES ( 1, 'Ardalan', 'Shahgholi' );
INSERT INTO #Employee VALUES ( 2, 'name1', 'lname1' );
INSERT INTO #Employee VALUES ( 3, 'name2', 'lname2' );
INSERT INTO #Employee VALUES ( 2, 'name1', 'lname1' );
INSERT INTO #Employee VALUES ( 3, 'name2', 'lname2' );
INSERT INTO #Employee VALUES ( 4, 'name3', 'lname3' );

첫 번째 해결책 :

SELECT DISTINCT *
FROM   #Employee;

WITH #DeleteEmployee AS (
                     SELECT ROW_NUMBER()
                            OVER(PARTITION BY ID, First_Name, Last_Name ORDER BY ID) AS
                            RNUM
                     FROM   #Employee
                 )

SELECT *
FROM   #DeleteEmployee
WHERE  RNUM > 1

SELECT DISTINCT *
FROM   #Employee

Secound 솔루션 : 사용 identity분야

SELECT DISTINCT *
FROM   #Employee;

ALTER TABLE #Employee ADD UNIQ_ID INT IDENTITY(1, 1)

SELECT *
FROM   #Employee
WHERE  UNIQ_ID < (
    SELECT MAX(UNIQ_ID)
    FROM   #Employee a2
    WHERE  #Employee.ID = a2.ID
           AND #Employee.FIRST_NAME = a2.FIRST_NAME
           AND #Employee.LAST_NAME = a2.LAST_NAME
)

ALTER TABLE #Employee DROP COLUMN UNIQ_ID

SELECT DISTINCT *
FROM   #Employee

모든 솔루션의 끝 에서이 명령을 사용하십시오.

DROP TABLE #Employee

0

나는 당신이 대답을 혼합하는 데 필요한 것을 알고 있다고 생각하며 그가 원하는 해결책을 얻었습니다.

select o.id,o.orgName, oc.dupeCount, oc.id,oc.orgName
from organizations o
inner join (
    SELECT MAX(id) as id, orgName, COUNT(*) AS dupeCount
    FROM organizations
    GROUP BY orgName
    HAVING COUNT(*) > 1
) oc on o.orgName = oc.orgName

최대 ID를 갖는 것은 사본의 ID와 그가 요청한 원본의 ID를 제공합니다.

id org name , dublicate count (missing out in this case) 
id doublicate org name , doub count (missing out again because does not help in this case)

슬프게도 당신이이 형태로 내 놓습니다

id , name , dubid , name

그것이 여전히 도움이되기를 바랍니다.


0

'Student'테이블에 2 개의 열이 있다고 가정 해 봅시다.

  • student_id int
  • student_name varchar

    Records:
    +------------+---------------------+
    | student_id | student_name        |
    +------------+---------------------+
    |        101 | usman               |
    |        101 | usman               |
    |        101 | usman               |
    |        102 | usmanyaqoob         |
    |        103 | muhammadusmanyaqoob |
    |        103 | muhammadusmanyaqoob |
    +------------+---------------------+

이제 중복 레코드를 보려고합니다.이 쿼리를 사용하십시오.

select student_name,student_id ,count(*) c from student group by student_id,student_name having c>1;

+---------------------+------------+---+
| student_name        | student_id | c |
+---------------------+------------+---+
| usman               |        101 | 3 |
| muhammadusmanyaqoob |        103 | 2 |
+---------------------+------------+---+

0

테이블에 중복 레코드를 얻는 더 좋은 옵션이 있습니다.

SELECT x.studid, y.stdname, y.dupecount
FROM student AS x INNER JOIN
(SELECT a.stdname, COUNT(*) AS dupecount
FROM student AS a INNER JOIN
studmisc AS b ON a.studid = b.studid
WHERE (a.studid LIKE '2018%') AND (b.studstatus = 4)
GROUP BY a.stdname
HAVING (COUNT(*) > 1)) AS y ON x.stdname = y.stdname INNER JOIN
studmisc AS z ON x.studid = z.studid
WHERE (x.studid LIKE '2018%') AND (z.studstatus = 4)
ORDER BY x.stdname

위 쿼리의 결과는 고유 한 학생 ID와 중복 발생 횟수를 가진 모든 중복 이름을 보여줍니다.

SQL의 결과를 보려면 여기를 클릭하십시오


0
 /*To get duplicate data in table */

 SELECT COUNT(EmpCode),EmpCode FROM tbl_Employees WHERE Status=1 
  GROUP BY EmpCode HAVING COUNT(EmpCode) > 1

0

중복 행을 찾기 위해 두 가지 방법을 사용합니다. 첫 번째 방법은 그룹별로 사용하는 것이 가장 유명한 방법입니다. 두 번째 방법은 CTE- Common Table Expression을 사용하는 것 입니다.

@RedFilter에서 언급 했듯이이 방법도 좋습니다. 여러 번 CTE 방법이 나에게도 유용하다는 것을 알았습니다.

WITH TempOrg (orgName,RepeatCount)
AS
(
SELECT orgName,ROW_NUMBER() OVER(PARTITION by orgName ORDER BY orgName) 
AS RepeatCount
FROM dbo.organizations
)
select t.*,e.id from organizations   e
inner join TempOrg t on t.orgName= e.orgName
where t.RepeatCount>1

위의 예에서 ROW_NUMBER 및 PARTITION BY를 사용하여 반복 발생을 찾아 결과를 수집했습니다. 그런 다음 where 절을 적용하여 반복 횟수가 1보다 많은 행만 선택했습니다. 모든 결과는 CTE 테이블을 수집하고 Organizations 테이블과 결합되었습니다.

출처 : CodoBee


-2

시험

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