Wie kann ich doppelte Zeilen entfernen?

1285

Was ist der beste Weg, um doppelte Zeilen aus einer ziemlich großen SQL ServerTabelle (dh mehr als 300.000 Zeilen) zu entfernen ?

Die Zeilen sind natürlich keine perfekten Duplikate, da das RowIDIdentitätsfeld vorhanden ist.

Mein Tisch

RowID int not null identity(1,1) primary key,
Col1 varchar(20) not null,
Col2 varchar(2048) not null,
Col3 tinyint not null
Seibar
quelle
13
Kurztipp für PostgreSQL-Benutzer, die dies lesen (viele davon hängen davon ab, wie oft es verknüpft ist): Pg macht CTE-Begriffe nicht als aktualisierbare Ansichten verfügbar, sodass Sie keinen DELETE FROMCTE-Begriff direkt verwenden können. Siehe stackoverflow.com/q/18439054/398670
Craig Ringer
@CraigRinger Gleiches gilt für Sybase - Ich habe die verbleibenden Lösungen hier gesammelt (sollte auch für PG und andere gültig sein: stackoverflow.com/q/19544489/1855801 (ersetzen Sie die ROWID()Funktion einfach durch die RowID-Spalte, falls vorhanden)
Maf-Soft
12
Nur um hier eine Einschränkung hinzuzufügen. Überprüfen Sie immer, was Sie zuerst löschen, wenn Sie einen Deduplizierungsprozess ausführen! Dies ist einer der Bereiche, in denen es sehr häufig vorkommt, dass gute Daten versehentlich gelöscht werden.
Jeff Davis

Antworten:

1142

Unter der Annahme, dass keine Nullen vorhanden sind, müssen Sie GROUP BYdie eindeutigen Spalten und SELECTdie MIN (or MAX)RowId als Zeile beibehalten. Löschen Sie dann einfach alles, was keine Zeilen-ID hatte:

DELETE FROM MyTable
LEFT OUTER JOIN (
   SELECT MIN(RowId) as RowId, Col1, Col2, Col3 
   FROM MyTable 
   GROUP BY Col1, Col2, Col3
) as KeepRows ON
   MyTable.RowId = KeepRows.RowId
WHERE
   KeepRows.RowId IS NULL

Wenn Sie eine GUID anstelle einer Ganzzahl haben, können Sie diese ersetzen

MIN(RowId)

mit

CONVERT(uniqueidentifier, MIN(CONVERT(char(36), MyGuidColumn)))
Mark Brackett
quelle
327
Würde das auch funktionieren? DELETE FROM MyTable WHERE RowId NOT IN (SELECT MIN(RowId) FROM MyTable GROUP BY Col1, Col2, Col3);
Georg Schölly
10
@Andriy - In SQL Server LEFT JOINist weniger effizient als NOT EXISTS sqlinthewild.co.za/index.php/2010/03/23/... Die gleiche Website vergleicht auch NOT INvs NOT EXISTS. sqlinthewild.co.za/index.php/2010/02/18/not-exists-vs-not-in Von den 3 ist meiner Meinung nach NOT EXISTSdie beste Leistung. Alle drei generieren einen Plan mit einem Self-Join, der jedoch vermieden werden kann.
Martin Smith
12
@Martin, @Georg: Also habe ich einen kleinen Test gemacht. Eine große Tabelle wurde wie hier beschrieben erstellt und gefüllt : sqlinthewild.co.za/index.php/2010/03/23/… Dann wurden zwei SELECTs erstellt, eine mit der Technik LEFT JOIN + WHERE IS NULL, die andere mit der Technik NOT In Eins. Dann fuhr ich mit den Hinrichtungsplänen fort und weißt du was? Die Abfragekosten betrugen 18% für LEFT JOIN gegenüber 82% für NOT IN, eine große Überraschung für mich. Ich hätte vielleicht etwas getan, was ich nicht hätte tun sollen oder umgekehrt, was ich, wenn es wahr wäre, wirklich gerne wissen würde.
Andriy M
16
@ GeorgSchölly hat eine elegante Antwort gegeben. Ich habe es für eine Tabelle verwendet, in der ein PHP-Fehler von mir doppelte Zeilen erstellt hat.
Philip Kearns
12
Entschuldigung, aber warum ist die DELETE MyTable FROM MyTableSyntax korrekt? Ich sehe nicht , die Tabellennamen direkt nach der Umsetzung DELETEals Option in der Dokumentation hier . Entschuldigung, wenn dies für andere offensichtlich ist. Ich bin ein Neuling in SQL und versuche nur zu lernen. Wichtiger als warum funktioniert es: Was ist der Unterschied zwischen dem Einfügen des Namens der Tabelle dort oder nicht?
Levininja
760

Ein anderer möglicher Weg, dies zu tun, ist

; 

--Ensure that any immediately preceding statement is terminated with a semicolon above
WITH cte
     AS (SELECT ROW_NUMBER() OVER (PARTITION BY Col1, Col2, Col3 
                                       ORDER BY ( SELECT 0)) RN
         FROM   #MyTable)
DELETE FROM cte
WHERE  RN > 1;

ich benutze ORDER BY (SELECT 0) oben, da es beliebig ist, welche Zeile im Falle eines Unentschieden beibehalten werden soll.

Um die neueste zu erhalten, können RowIDSie sie beispielsweise verwendenORDER BY RowID DESC

Ausführungspläne

Der Ausführungsplan hierfür ist häufig einfacher und effizienter als der in der akzeptierten Antwort, da keine Selbstverbindung erforderlich ist.

Ausführungspläne

Dies ist jedoch nicht immer der Fall. Ein Ort, an dem die GROUP BYLösung bevorzugt werden könnte, sind Situationen, in denen ein Hash-Aggregat einem Stream-Aggregat vorgezogen wird .

Die ROW_NUMBERLösung wird immer fast den gleichen Plan geben, während die GROUP BYStrategie flexibler ist.

Ausführungspläne

Faktoren, die den Hash-Aggregat-Ansatz begünstigen könnten, wären

  • Kein nützlicher Index für die Partitionierungsspalten
  • relativ weniger Gruppen mit relativ mehr Duplikaten in jeder Gruppe

In extremen Versionen dieses zweiten Falls (wenn es nur sehr wenige Gruppen mit jeweils vielen Duplikaten gibt) könnte man auch in Betracht ziehen, einfach die Zeilen einzufügen, um sie in einer neuen Tabelle zu behalten, dann TRUNCATEdas Original zu kopieren und sie zurück zu kopieren, um die Protokollierung im Vergleich zum Löschen von a zu minimieren sehr hoher Anteil der Reihen.

Martin Smith
quelle
28
Wenn ich hinzufügen darf: Die akzeptierte Antwort funktioniert nicht mit Tabellen, die verwendet werden uniqueidentifier. Dieser ist viel einfacher und funktioniert perfekt auf jedem Tisch. Danke Martin.
BrunoLM
15
Das ist so eine tolle Antwort! Es funktionierte, als ich die alte PK entfernt hatte, bevor mir klar wurde, wo Duplikate waren. +100
Mikael Eliasson
12
Ich schlage vor, diese Frage (mit dieser Antwort) auf DBA.SE zu stellen und dann zu beantworten. Dann können wir es unserer Liste kanonischer Antworten hinzufügen .
Nick Chammas
16
Im Gegensatz zur akzeptierten Antwort funktionierte dies auch für eine Tabelle, für die es keinen Schlüssel ( RowId) zum Vergleichen gab.
Vossad01
8
Dieser funktioniert nicht auf allen SQL Server-Versionen
David
150

Es gibt einen guten Artikel zum Entfernen von Duplikaten auf der Microsoft Support-Website. Es ist ziemlich konservativ - Sie müssen alles in separaten Schritten erledigen - aber es sollte gut gegen große Tische funktionieren.

Ich habe in der Vergangenheit Self-Joins verwendet, um dies zu tun, obwohl es wahrscheinlich mit einer HAVING-Klausel verschönert werden könnte:

DELETE dupes
FROM MyTable dupes, MyTable fullTable
WHERE dupes.dupField = fullTable.dupField 
AND dupes.secondDupField = fullTable.secondDupField 
AND dupes.uniqueField > fullTable.uniqueField
Jon Galloway
quelle
perfekt! Ich fand, dass dies der effizienteste Weg ist, um doppelte Zeilen auf meiner alten Mariadb-Version 10.1.xx zu entfernen. Vielen Dank!
Betrunkener M
Viel einfacher und verständlicher!
Marc
98

Die folgende Abfrage ist nützlich, um doppelte Zeilen zu löschen. Die Tabelle in diesem Beispiel IDals Identitätsspalte und die Spalten , die doppelten Daten sind Column1, Column2und Column3.

DELETE FROM TableName
WHERE  ID NOT IN (SELECT MAX(ID)
                  FROM   TableName
                  GROUP  BY Column1,
                            Column2,
                            Column3
                  /*Even if ID is not null-able SQL Server treats MAX(ID) as potentially
                    nullable. Because of semantics of NOT IN (NULL) including the clause
                    below can simplify the plan*/
                  HAVING MAX(ID) IS NOT NULL) 

Die folgende Skript zeigt Verwendung von GROUP BY, HAVING, ORDER BYin einer Abfrage, und gibt die Ergebnisse mit doppelter Spalte und seiner Zählung.

SELECT YourColumnName,
       COUNT(*) TotalCount
FROM   YourTableName
GROUP  BY YourColumnName
HAVING COUNT(*) > 1
ORDER  BY COUNT(*) DESC 
gngolakia
quelle
1
MySQL-Fehler mit dem ersten Skript 'Sie können die Zieltabelle' TableName 'für die Aktualisierung in der FROM-Klausel nicht angeben'
D.Rosado
Abgesehen von dem bereits gemeldeten Fehler D.Rosado ist Ihre erste Abfrage auch sehr langsam. Die entsprechende SELECT-Abfrage dauerte in meinem Setup + - 20 Mal länger als die akzeptierte Antwort.
Parvus
8
@parvus - Die Frage ist mit SQL Server und nicht mit MySQL gekennzeichnet. Die Syntax ist in SQL Server in Ordnung. Auch MySQL ist bekanntermaßen schlecht darin, Unterabfragen zu optimieren, siehe zum Beispiel hier . Diese Antwort ist in SQL Server in Ordnung. In der Tat NOT INoft besser als OUTER JOIN ... NULL. Ich würde ein hinzufügen , HAVING MAX(ID) IS NOT NULLum die Abfrage obwohl obwohl semantisch es nicht notwendig sein sollte wie den Plan zu verbessern Beispiel , dass hier
Martin Smith
2
Funktioniert hervorragend in PostgreSQL 8.4.
nortally
63
delete t1
from table t1, table t2
where t1.columnA = t2.columnA
and t1.rowid>t2.rowid

Postgres:

delete
from table t1
using table t2
where t1.columnA = t2.columnA
and t1.rowid > t2.rowid
SoftwareGeek
quelle
Warum eine Postgres-Lösung auf einer SQL Server-Frage veröffentlichen?
Lankymart
2
@Lankymart Weil auch Postgres-Benutzer hierher kommen. Schauen Sie sich die Punktzahl dieser Antwort an.
Gabriel
2
Ich habe dies in einigen populären SQL-Fragen gesehen, wie hier , hier und hier . Das OP bekam seine Antwort und alle anderen bekamen auch Hilfe. Kein Problem IMHO.
Gabriel
44
DELETE LU 
FROM   (SELECT *, 
               Row_number() 
                 OVER ( 
                   partition BY col1, col1, col3 
                   ORDER BY rowid DESC) [Row] 
        FROM   mytable) LU 
WHERE  [row] > 1 
Jithin Shaji
quelle
1
Ich erhalte diese Meldung in Azure SQL DW: Eine FROM-Klausel wird derzeit in einer DELETE-Anweisung nicht unterstützt.
Amit
40

Dadurch werden doppelte Zeilen mit Ausnahme der ersten Zeile gelöscht

DELETE
FROM
    Mytable
WHERE
    RowID NOT IN (
        SELECT
            MIN(RowID)
        FROM
            Mytable
        GROUP BY
            Col1,
            Col2,
            Col3
    )

Siehe ( http://www.codeproject.com/Articles/157977/Remove-Duplicate-Rows-from-a-Table-in-SQL-Server )

Syed Mohamed
quelle
10
Für MySQL wird der folgende Fehler ausgegeben: Fehlercode: 1093. Sie können die Zieltabelle 'Mytable' für die Aktualisierung in der FROM-Klausel nicht angeben. Diese kleine Änderung funktioniert jedoch für MySQL: DELETE FROM Mytable WHERE RowID NICHT IN (SELECT ID FROM (SELECT MIN (RowID) AS ID FROM Mytable GROUP BY Col1, Col2, Col3) AS TEMP)
Ritesh
35

Ich würde CTE bevorzugen, um doppelte Zeilen aus der SQL Server-Tabelle zu löschen

Es wird dringend empfohlen, diesem Artikel zu folgen: http://codaffection.com/sql-server-article/delete-duplicate-rows-in-sql-server/

indem Sie das Original behalten

WITH CTE AS
(
SELECT *,ROW_NUMBER() OVER (PARTITION BY col1,col2,col3 ORDER BY col1,col2,col3) AS RN
FROM MyTable
)

DELETE FROM CTE WHERE RN<>1

ohne das Original zu behalten

WITH CTE AS
(SELECT *,R=RANK() OVER (ORDER BY col1,col2,col3)
FROM MyTable)
 
DELETE CTE
WHERE R IN (SELECT R FROM CTE GROUP BY R HAVING COUNT(*)>1)
Shamseer K.
quelle
24

So rufen Sie doppelte Zeilen ab:

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

So löschen Sie die doppelten Zeilen:

DELETE users 
WHERE rowid NOT IN 
(SELECT MIN(rowid)
FROM users
GROUP BY name, email);      
Shaini Sinha
quelle
Beachten Sie für MySQL-Benutzer, dass es erstens sein muss DELETE FROMund zweitens nicht funktioniert, da Sie nicht SELECTaus derselben Tabelle stammen können, aus der Sie stammen DELETE. In MySQL sprengt dies MySQL error 1093.
Mhor Mé
23

Schnell und fehlerhaft, um exakte doppelte Zeilen zu löschen (für kleine Tabellen):

select  distinct * into t2 from t1;
delete from t1;
insert into t1 select *  from t2;
drop table t2;
JuanJo
quelle
3
Beachten Sie, dass die Frage tatsächlich eine nicht exakte Duplizierung angibt (Dueto-Zeilen-ID).
Dennis Jaheruddin
21

Ich bevorzuge die Unterabfrage \ mit count (*)> 1-Lösung gegenüber der inneren Verknüpfung, da ich sie leichter lesen konnte und es sehr einfach war, sie in eine SELECT-Anweisung umzuwandeln, um zu überprüfen, was gelöscht werden würde, bevor Sie sie ausführen.

--DELETE FROM table1 
--WHERE id IN ( 
     SELECT MIN(id) FROM table1 
     GROUP BY col1, col2, col3 
     -- could add a WHERE clause here to further filter
     HAVING count(*) > 1
--)
James Errico
quelle
Löscht es nicht alle Datensätze, die in der inneren Abfrage angezeigt werden. Wir müssen nur Duplikate entfernen und das Original erhalten.
Sandy
3
Sie geben nur die mit der niedrigsten ID zurück, basierend auf der min (id) in der select-Klausel.
James Errico
2
Kommentieren Sie die erste, zweite und letzte Zeile der Abfrage aus.
James Errico
7
Dadurch werden nicht alle Duplikate bereinigt. Wenn Sie 3 Zeilen haben, die Duplikate sind, wird nur die Zeile mit der MIN (ID) ausgewählt und diese gelöscht, wobei zwei Zeilen übrig bleiben, die Duplikate sind.
Chloe
2
Trotzdem habe ich diese Anweisung immer wieder verwendet, damit sie tatsächlich Fortschritte macht, anstatt das Zeitlimit für die Verbindung zu überschreiten oder den Computer in den Ruhezustand zu versetzen. Ich habe es geändert MAX(id), um die letzteren Duplikate zu entfernen, und LIMIT 1000000der inneren Abfrage hinzugefügt , damit nicht die gesamte Tabelle gescannt werden muss. Dies zeigte Fortschritte viel schneller als die anderen Antworten, die stundenlang zu hängen scheinen. Nachdem die Tabelle auf eine überschaubare Größe beschnitten wurde, können Sie mit den anderen Abfragen fertig werden. Tipp: Stellen Sie sicher, dass col1 / col2 / col3 Indizes für die Gruppierung nach enthält.
Chloe
17
SELECT  DISTINCT *
      INTO tempdb.dbo.tmpTable
FROM myTable

TRUNCATE TABLE myTable
INSERT INTO myTable SELECT * FROM tempdb.dbo.tmpTable
DROP TABLE tempdb.dbo.tmpTable
heta77
quelle
5
Das Abschneiden funktioniert nicht, wenn Sie Fremdschlüsselverweise auf myTable haben.
Sameer Alibhai
15

Ich dachte, ich würde meine Lösung teilen, da sie unter besonderen Umständen funktioniert. In meinem Fall hatte die Tabelle mit doppelten Werten keinen Fremdschlüssel (da die Werte von einer anderen Datenbank dupliziert wurden).

begin transaction
-- create temp table with identical structure as source table
Select * Into #temp From tableName Where 1 = 2

-- insert distinct values into temp
insert into #temp 
select distinct * 
from  tableName

-- delete from source
delete from tableName 

-- insert into source from temp
insert into tableName 
select * 
from #temp

rollback transaction
-- if this works, change rollback to commit and execute again to keep you changes!!

PS: Wenn ich an solchen Dingen arbeite, verwende ich immer eine Transaktion. Dadurch wird nicht nur sichergestellt, dass alles als Ganzes ausgeführt wird, sondern ich kann auch testen, ohne etwas zu riskieren. Aber natürlich sollten Sie trotzdem ein Backup erstellen, nur um sicherzugehen ...

Ruben Verschueren
quelle
14

Diese Abfrage zeigte eine sehr gute Leistung für mich:

DELETE tbl
FROM
    MyTable tbl
WHERE
    EXISTS (
        SELECT
            *
        FROM
            MyTable tbl2
        WHERE
            tbl2.SameValue = tbl.SameValue
        AND tbl.IdUniqueValue < tbl2.IdUniqueValue
    )

Es löschte 1 Million Zeilen in etwas mehr als 30 Sekunden aus einer Tabelle mit 2 Millionen (50% Duplikate).

Draško
quelle
14

CTE verwenden. Die Idee ist, eine oder mehrere Spalten zu verbinden, die einen doppelten Datensatz bilden, und dann zu entfernen, was immer Sie möchten:

;with cte as (
    select 
        min(PrimaryKey) as PrimaryKey
        UniqueColumn1,
        UniqueColumn2
    from dbo.DuplicatesTable 
    group by
        UniqueColumn1, UniqueColumn1
    having count(*) > 1
)
delete d
from dbo.DuplicatesTable d 
inner join cte on 
    d.PrimaryKey > cte.PrimaryKey and
    d.UniqueColumn1 = cte.UniqueColumn1 and 
    d.UniqueColumn2 = cte.UniqueColumn2;
Ostati
quelle
1
Ich denke, Sie vermissen ein UND in Ihrem JOIN.
Justin R.
13

Eine weitere einfache Lösung finden Sie unter dem hier eingefügten Link . Dieser ist leicht zu verstehen und scheint für die meisten ähnlichen Probleme effektiv zu sein. Es ist zwar für SQL Server, aber das verwendete Konzept ist mehr als akzeptabel.

Hier sind die relevanten Teile der verlinkten Seite:

Betrachten Sie diese Daten:

EMPLOYEE_ID ATTENDANCE_DATE
A001    2011-01-01
A001    2011-01-01
A002    2011-01-01
A002    2011-01-01
A002    2011-01-01
A003    2011-01-01

Wie können wir diese doppelten Daten löschen?

Fügen Sie zunächst eine Identitätsspalte in diese Tabelle ein, indem Sie den folgenden Code verwenden:

ALTER TABLE dbo.ATTENDANCE ADD AUTOID INT IDENTITY(1,1)  

Verwenden Sie den folgenden Code, um das Problem zu beheben:

DELETE FROM dbo.ATTENDANCE WHERE AUTOID NOT IN (SELECT MIN(AUTOID) _
    FROM dbo.ATTENDANCE GROUP BY EMPLOYEE_ID,ATTENDANCE_DATE) 
Nitish Pareek
quelle
1
„Leicht zu begreifen“, „scheint um wirksam zu sein“, aber kein Wort über das, was die Methode besteht darin. Man stelle sich vor , dass der Link ungültig wird, was würde die Verwendung dann wissen zu , dass das Verfahren war leicht zu verstehen und effektiv? Bitte erwägen Sie, wesentliche Teile der Methodenbeschreibung in Ihren Beitrag aufzunehmen, da dies sonst keine Antwort ist.
Andriy M
Diese Methode ist nützlich für Tabellen, für die noch keine Identität definiert ist. Oft müssen Sie Duplikate entfernen, um den Primärschlüssel zu definieren!
Jeff Davis
@JeffDavis - Die ROW_NUMBERVersion funktioniert in diesem Fall einwandfrei , ohne dass Sie vor Beginn eine neue Spalte hinzufügen müssen.
Martin Smith
12

Hier ist ein weiterer guter Artikel zum Entfernen von Duplikaten .

Es wird erläutert, warum es schwierig ist: " SQL basiert auf relationaler Algebra, und Duplikate können in der relationalen Algebra nicht auftreten, da Duplikate in einer Menge nicht zulässig sind. "

Die temporäre Tabellenlösung und zwei MySQL-Beispiele.

In Zukunft werden Sie dies auf Datenbankebene oder aus Anwendungssicht verhindern. Ich würde die Datenbankebene vorschlagen, da Ihre Datenbank für die Aufrechterhaltung der referenziellen Integrität verantwortlich sein sollte. Entwickler werden nur Probleme verursachen;)

Craig
quelle
1
SQL basiert auf mehreren Mengen. Aber selbst wenn es auf Mengen basiert, sind diese beiden Tupel (1, a) und (2, a) unterschiedlich.
Andrew
12

Oh sicher. Verwenden Sie eine temporäre Tabelle. Wenn Sie eine einzelne, nicht sehr performante Aussage wünschen, die "funktioniert", können Sie folgendermaßen vorgehen:

DELETE FROM MyTable WHERE NOT RowID IN
    (SELECT 
        (SELECT TOP 1 RowID FROM MyTable mt2 
        WHERE mt2.Col1 = mt.Col1 
        AND mt2.Col2 = mt.Col2 
        AND mt2.Col3 = mt.Col3) 
    FROM MyTable mt)

Grundsätzlich findet die Unterauswahl für jede Zeile in der Tabelle die oberste Zeilen-ID aller Zeilen, die genau der betrachteten Zeile entsprechen. Am Ende erhalten Sie eine Liste von RowIDs, die die "ursprünglichen" nicht duplizierten Zeilen darstellen.

Jacob Proffitt
quelle
11

Ich hatte eine Tabelle, in der ich nicht doppelte Zeilen beibehalten musste. Ich bin mir nicht sicher über die Geschwindigkeit oder Effizienz.

DELETE FROM myTable WHERE RowID IN (
  SELECT MIN(RowID) AS IDNo FROM myTable
  GROUP BY Col1, Col2, Col3
  HAVING COUNT(*) = 2 )
chrismar035
quelle
7
Dies setzt voraus, dass es höchstens 1 Duplikat gibt.
Martin Smith
Warum nicht HAVING COUNT(*) > 1?
Philipp M
11

Benutze das

WITH tblTemp as
(
SELECT ROW_NUMBER() Over(PARTITION BY Name,Department ORDER BY Name)
   As RowNumber,* FROM <table_name>
)
DELETE FROM tblTemp where RowNumber >1
Haris
quelle
10

Die andere Möglichkeit besteht darin, eine neue Tabelle mit denselben Feldern und mit einem eindeutigen Index zu erstellen . Dann bewegen sich alle Daten aus altem Tisch zu neuer Tabelle . Automatisch ignorieren SQL SERVER (es gibt auch eine Option, was zu tun ist, wenn ein doppelter Wert vorliegt: ignorieren, unterbrechen oder etw) doppelte Werte. Wir haben also dieselbe Tabelle ohne doppelte Zeilen. Wenn Sie keinen eindeutigen Index möchten, können Sie ihn nach den Übertragungsdaten löschen .

Insbesondere für größere Tabellen können Sie DTS (SSIS-Paket zum Importieren / Exportieren von Daten) verwenden, um alle Daten schnell in Ihre neue eindeutig indizierte Tabelle zu übertragen. Für 7 Millionen Reihen dauert es nur wenige Minuten.

İsmail Yavuz
quelle
9

Mit der folgenden Abfrage können wir doppelte Datensätze löschen, die auf der einzelnen oder mehreren Spalten basieren. Die folgende Abfrage wird basierend auf zwei Spalten gelöscht. Tabellenname ist: testingund Spaltennamenempno,empname

DELETE FROM testing WHERE empno not IN (SELECT empno FROM (SELECT empno, ROW_NUMBER() OVER (PARTITION BY empno ORDER BY empno) 
AS [ItemNumber] FROM testing) a WHERE ItemNumber > 1)
or empname not in
(select empname from (select empname,row_number() over(PARTITION BY empno ORDER BY empno) 
AS [ItemNumber] FROM testing) a WHERE ItemNumber > 1)
Sudhakar NV
quelle
9
  1. Erstellen Sie eine neue leere Tabelle mit derselben Struktur

  2. Führen Sie die Abfrage wie folgt aus

    INSERT INTO tc_category1
    SELECT *
    FROM tc_category
    GROUP BY category_id, application_id
    HAVING count(*) > 1
  3. Führen Sie dann diese Abfrage aus

    INSERT INTO tc_category1
    SELECT *
    FROM tc_category
    GROUP BY category_id, application_id
    HAVING count(*) = 1
shA.t.
quelle
9

Dies ist der einfachste Weg, um doppelte Datensätze zu löschen

 DELETE FROM tblemp WHERE id IN 
 (
  SELECT MIN(id) FROM tblemp
   GROUP BY  title HAVING COUNT(id)>1
 )

http://askme.indianyouth.info/details/how-to-dumplicate-record-from-table-in-using-sql-105

Harikesh Yadav
quelle
Warum stimmt jemand dem zu? Wenn Sie mehr als zwei derselben ID haben, funktioniert dies NICHT. Schreiben Sie stattdessen: Löschen Sie aus Tblemp, wo ID nicht in (wählen Sie min (ID) aus der Tblemp-Gruppe nach Titel)
Crellee
7

Ich würde diesen Ansatz erwähnen, da er hilfreich sein kann und auf allen SQL-Servern funktioniert: Ziemlich oft gibt es nur ein - zwei Duplikate, und IDs und Anzahl der Duplikate sind bekannt. In diesem Fall:

SET ROWCOUNT 1 -- or set to number of rows to be deleted
delete from myTable where RowId = DuplicatedID
SET ROWCOUNT 0
Evgueny Sedov
quelle
7

Von der Anwendungsebene (leider). Ich bin damit einverstanden, dass die ordnungsgemäße Methode zum Verhindern von Duplikaten auf Datenbankebene durch die Verwendung eines eindeutigen Index erfolgt. In SQL Server 2005 darf ein Index jedoch nur 900 Byte groß sein, und mein Feld varchar (2048) bläst dies weg.

Ich weiß nicht, wie gut es funktionieren würde, aber ich denke, Sie könnten einen Auslöser schreiben, um dies zu erzwingen, selbst wenn Sie es nicht direkt mit einem Index tun könnten. Etwas wie:

-- given a table stories(story_id int not null primary key, story varchar(max) not null)
CREATE TRIGGER prevent_plagiarism 
ON stories 
after INSERT, UPDATE 
AS 
    DECLARE @cnt AS INT 

    SELECT @cnt = Count(*) 
    FROM   stories 
           INNER JOIN inserted 
                   ON ( stories.story = inserted.story 
                        AND stories.story_id != inserted.story_id ) 

    IF @cnt > 0 
      BEGIN 
          RAISERROR('plagiarism detected',16,1) 

          ROLLBACK TRANSACTION 
      END 

Außerdem klingt varchar (2048) für mich faul (einige Dinge im Leben sind 2048 Bytes, aber es ist ziemlich ungewöhnlich); sollte es wirklich nicht varchar (max) sein?

DrPizza
quelle
7

Eine andere Möglichkeit, dies zu tun:

DELETE A
FROM   TABLE A,
       TABLE B
WHERE  A.COL1 = B.COL1
       AND A.COL2 = B.COL2
       AND A.UNIQUEFIELD > B.UNIQUEFIELD 
Yuvi
quelle
Was unterscheidet sich von dieser bestehenden Antwort vom 20. August 2008? - stackoverflow.com/a/18934/692942
Lankymart
7
DELETE
FROM
    table_name T1
WHERE
    rowid > (
        SELECT
            min(rowid)
        FROM
            table_name T2
        WHERE
            T1.column_name = T2.column_name
    );
Teena
quelle
Hallo Teena, du hast die Tabelle Alice Name T1 nach dem Löschkommentar verpasst, sonst wird es eine Syntaxausnahme geben.
Nagaraj M
6
CREATE TABLE car(Id int identity(1,1), PersonId int, CarId int)

INSERT INTO car(PersonId,CarId)
VALUES(1,2),(1,3),(1,2),(2,4)

--SELECT * FROM car

;WITH CTE as(
SELECT ROW_NUMBER() over (PARTITION BY personid,carid order by personid,carid) as rn,Id,PersonID,CarId from car)

DELETE FROM car where Id in(SELECT Id FROM CTE WHERE rn>1)
AnandPhadke
quelle
6

Ich möchte eine Vorschau der Zeilen anzeigen, die Sie entfernen möchten, und die Kontrolle darüber behalten, welche der doppelten Zeilen beibehalten werden sollen. Siehe http://developer.azurewebsites.net/2014/09/better-sql-group-by-find-duplicate-data/

with MYCTE as (
  SELECT ROW_NUMBER() OVER (
    PARTITION BY DuplicateKey1
                ,DuplicateKey2 -- optional
    ORDER BY CreatedAt -- the first row among duplicates will be kept, other rows will be removed
  ) RN
  FROM MyTable
)
DELETE FROM MYCTE
WHERE RN > 1
Lauri Lubi
quelle