Suchen doppelter Zeilen in SQL Server


230

Ich habe eine SQL Server-Datenbank mit Organisationen und es gibt viele doppelte Zeilen. Ich möchte eine select-Anweisung ausführen, um alle diese und die Anzahl der Dupes abzurufen, aber auch die IDs zurückgeben, die jeder Organisation zugeordnet sind.

Eine Aussage wie:

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

Wird so etwas zurückgeben

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

Aber ich würde auch gerne die Ausweise von ihnen greifen. Gibt es eine Möglichkeit, dies zu tun? Vielleicht wie ein

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

Der Grund dafür ist, dass es auch eine separate Tabelle mit Benutzern gibt, die mit diesen Organisationen verknüpft sind, und ich möchte sie vereinheitlichen (entfernen Sie daher Dupes, damit die Benutzer mit derselben Organisation verknüpfen, anstatt Organisationen zu betrügen). Aber ich möchte ein Teil manuell, damit ich nichts vermassle, aber ich würde trotzdem eine Anweisung benötigen, die die IDs aller betrogenen Organisationen zurückgibt, damit ich die Liste der Benutzer durchgehen kann.

Antworten:


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
Gibt es Einschränkungen bei dieser Abfrage, z. B. wenn die Anzahl der Datensätze mehr als 10 Millionen beträgt?
Steam

3
@Steam Sie haben Recht: Diese Antwort ist in einer größeren Datenbank mit Millionen von Datensätzen nicht effizient. Bevorzugen Sie die von Aykut übermittelte GroupBy / Answer-Antwort, die von der Datenbank besser optimiert werden kann. Eine Ausnahme: Ich schlage vor, Count (0) anstelle von Count (*) zu verwenden, um die Dinge zu vereinfachen.
Mike Christian

1
@Mike - warum Count (0) vs Count (*)?
KornMuffin

2
@KornMuffin Rückblickend ist mein Kommentar zu Count () nichtig. Die Verwendung einer Nicht-Null-Auswertung in Count () ist nur dann nützlich, wenn Sie Nicht-Null-Ergebnisse zählen möchten, die von einem äußeren Join zurückgegeben werden. Verwenden Sie andernfalls Count (*). Eine gute Erklärung finden Sie hier .
Mike Christian

Verwendung isnull()für nullfähige Spalten im onAbschnitt
Arif Ulusoy

92

Sie können die folgende Abfrage ausführen und die Duplikate mit max(id)diesen Zeilen suchen und löschen.

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

Sie müssen diese Abfrage jedoch einige Male ausführen.


Sie müssen es genau MAX( COUNT(*) ) - 1mal ausführen , was möglicherweise noch möglich ist.
DerMike

1
Hallo, ist es eine Möglichkeit, alle IDs anstelle der Max-ID zu erhalten, wie bei 2? Ich kann Max und Min verwenden, aber was ist mit mehr als 2? @DerMike
Arijit Mukherjee

31

Sie können es so machen:

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

Wenn Sie nur die Datensätze zurückgeben möchten, die gelöscht werden können (wobei jeweils einer übrig bleibt), können Sie Folgendes verwenden:

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

Bearbeiten: SQL Server 2000 verfügt nicht über die Funktion ROW_NUMBER (). Stattdessen können Sie Folgendes verwenden:

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

Die erste Aussage funktioniert, aber die zweite scheint nicht zu funktionieren.
xtine

SQL Server scheint row_number () nicht erkennen zu können?
xtine

Ah ... haben Sie eine ältere Version von SQL Server? Ich glaube, es wurde in SQL Server 2005 eingeführt.
Paul


9

Die als korrekt gekennzeichnete Lösung hat bei mir nicht funktioniert, aber ich fand diese Antwort einfach großartig: Liste der doppelten Zeilen in MySql abrufen

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

Sie werden viele Dupes in der Ergebnismenge haben, also müssen Sie sich auch mit diesen befassen.
Renan

1
Wenn die ID numerisch ist, n1.id > n2.idverhindert die Überprüfung , dass jedes Paar zweimal angezeigt wird.
Starwed

9

Sie können dies versuchen, es ist am besten für Sie

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

jede Möglichkeit, alle IDs in Kommasplits oder verschiedenen Spalten zu erhalten
Arijit Mukherjee

6

Wenn Sie Duplikate löschen möchten:

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]

So finden Sie doppelte Datensätze 1) Verwenden von 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) Mit GroupBy

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

Dies ist hier die schnellste Lösung, wenn Daten über 10 m Zeilen ausgewählt werden. Vielen Dank
Fandango68

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

Die Datensätze mit rowum> 1 sind also die doppelten Datensätze in Ihrer Tabelle. 'Partition by' gruppiert zuerst die Datensätze und serialisiert sie dann, indem Sie ihnen die Seriennummern geben. Rownum> 1 sind also die doppelten Datensätze, die als solche gelöscht werden könnten.


Ich mag dieses, weil es Ihnen ermöglicht, einfach mehr Spalten in die innere Auswahlklausel einzufügen. Wenn Sie also andere Spalten aus der Tabelle "Organisationen" zurückgeben möchten, müssen Sie für diese Spalten keine "Gruppierung nach" durchführen.
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

Sie haben mehrere Möglichkeiten für Select duplicate rows.

Betrachten Sie für meine Lösungen zunächst diese Tabelle

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' );

Erste Lösung:

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

Zweite Lösung: identityFeld verwenden

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

und Ende aller Lösungen verwenden Sie diesen Befehl

DROP TABLE #Employee

0

Ich glaube, ich weiß, was du brauchst. Ich musste zwischen den Antworten mischen und ich glaube, ich habe die Lösung, die er wollte:

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

Wenn Sie die maximale ID haben, erhalten Sie die ID des Republikaners und die des Originals, nach der er gefragt hat:

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)

nur traurig, dass du es in dieser Form herausbringst

id , name , dubid , name

hoffe es hilft noch


0

Angenommen, wir haben die Tabelle 'Student' mit 2 Spalten in der Tabelle:

  • student_id int
  • student_name varchar

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

Jetzt möchten wir doppelte Datensätze sehen. Verwenden Sie diese Abfrage:

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

Ich habe eine bessere Option, um die doppelten Datensätze in einer Tabelle zu erhalten

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

Das Ergebnis der obigen Abfrage zeigt alle doppelten Namen mit eindeutigen Schüler-IDs und der Anzahl der doppelten Vorkommen

Klicken Sie hier, um das Ergebnis der SQL zu sehen


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

Ich benutze zwei Methoden, um doppelte Zeilen zu finden. Die erste Methode ist die bekannteste, bei der Gruppen von und mit verwendet werden. Die zweite Methode verwendet CTE - Common Table Expression .

Wie von @RedFilter erwähnt, ist dieser Weg auch richtig. Oft finde ich, dass die CTE-Methode auch für mich nützlich ist.

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

Im obigen Beispiel haben wir das Ergebnis gesammelt, indem wir das wiederholte Auftreten mit ROW_NUMBER und PARTITION BY ermittelt haben. Dann haben wir die where-Klausel angewendet, um nur Zeilen auszuwählen, deren Wiederholungszahl mehr als 1 beträgt. Das gesamte Ergebnis wird in der CTE-Tabelle gesammelt und mit der Organisationstabelle verknüpft.

Quelle: CodoBee


-2

Versuchen

SELECT orgName, id, count(*) as dupes
FROM organizations
GROUP BY orgName, id
HAVING count(*) > 1;
Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.