1375 Stimmen

Wie kann ich doppelte Zeilen entfernen?

Wie entfernt man am besten doppelte Zeilen aus einer ziemlich großen SQL Server Tabelle (d.h. 300.000+ Zeilen)?

Die Zeilen werden natürlich keine perfekten Duplikate sein, da es die RowID Identitätsfeld.

MyTable

RowID int not null identity(1,1) primary key,
Col1 varchar(20) not null,
Col2 varchar(2048) not null,
Col3 tinyint not null

15 Stimmen

Kleiner Tipp für PostgreSQL-Benutzer, die dies lesen (viele, wenn man bedenkt, wie oft es verlinkt wird): Pg stellt CTE-Terme nicht als aktualisierbare Views zur Verfügung, so dass Sie nicht DELETE FROM ein CTE-Begriff direkt. Siehe stackoverflow.com/q/18439054/398670

0 Stimmen

@CraigRinger das gleiche gilt für Sybase - Die übrigen Lösungen habe ich hier zusammengestellt (sollten auch für PG und andere gelten): stackoverflow.com/q/19544489/1855801 (ersetzen Sie einfach die ROWID() Funktion durch die Spalte RowID, falls vorhanden)

14 Stimmen

Ich möchte hier nur einen Vorbehalt anbringen. Wenn Sie einen Deduplizierungsprozess durchführen, überprüfen Sie immer zuerst, was Sie löschen! Dies ist einer der Bereiche, in denen es sehr häufig vorkommt, dass versehentlich gute Daten gelöscht werden.

1194voto

Mark Brackett Punkte 83046

Unter der Annahme, dass es keine Nullen gibt, können Sie GROUP BY die eindeutigen Spalten, und SELECT el MIN (or MAX) RowId als die zu behaltende Zeile. Dann löschen Sie einfach alles, was keine RowId hat:

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

Falls Sie eine GUID anstelle einer Ganzzahl haben, können Sie die

MIN(RowId)

avec

CONVERT(uniqueidentifier, MIN(CONVERT(char(36), MyGuidColumn)))

351 Stimmen

Würde das auch funktionieren? DELETE FROM MyTable WHERE RowId NOT IN (SELECT MIN(RowId) FROM MyTable GROUP BY Col1, Col2, Col3);

1 Stimmen

Tolle Lösung! Scheint, dass man für PostgreSQL eine Subquery mehr braucht wie in gist.github.com/754805

0 Stimmen

@Georg: Ich denke, das würde es. Ihre Lösung ist kürzer und übersichtlicher. Ich bin mir nicht so sicher, was die Leistung angeht, vielleicht ist sie gleichwertig mit der von Mark, aber bei wirklich großen Tabellen würde ich wahrscheinlich bei LEFT JOIN bleiben.

795voto

Martin Smith Punkte 417623

Eine andere Möglichkeit 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 verwende ORDER BY (SELECT 0) oben, da es willkürlich ist, welche Zeile im Falle eines Gleichstands erhalten bleibt.

Um die letzte in RowID Bestellung könnten Sie zum Beispiel verwenden ORDER BY RowID DESC

Ausführungspläne

Der Ausführungsplan hierfür ist oft einfacher und effizienter als der in der akzeptierten Antwort, da er die Selbstverknüpfung nicht erfordert.

Execution Plans

Dies ist jedoch nicht immer der Fall. Ein Ort, an dem die GROUP BY Lösung könnte in Situationen bevorzugt werden, in denen ein Hash-Aggregat würde einem Stromaggregat vorgezogen werden.

Le site ROW_NUMBER Lösung wird immer so ziemlich den gleichen Plan ergeben, während die GROUP BY Die Strategie ist flexibler.

Execution Plans

Faktoren, die für den Hash-Aggregat-Ansatz sprechen könnten, wären

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

In extremen Versionen dieses zweiten Falls (wenn es sehr wenige Gruppen mit vielen Duplikaten in jeder gibt) könnte man auch erwägen, die zu behaltenden Zeilen einfach in eine neue Tabelle einzufügen und dann TRUNCATE -Originalen und dem Zurückkopieren, um die Protokollierung zu minimieren, im Vergleich zum Löschen eines sehr hohen Anteils der Zeilen.

31 Stimmen

Wenn ich hinzufügen darf: Die akzeptierte Antwort funktioniert nicht mit Tabellen, die uniqueidentifier . Diese ist viel einfacher und funktioniert perfekt auf jedem Tisch. Danke Martin.

1 Stimmen

Dies ist die einzige Lösung, die für meine große Tabelle (30 Mio. Zeilen) praktikabel ist. Ich wünschte, ich könnte ihr mehr als +1 geben

15 Stimmen

Das ist eine großartige Antwort! Es funktionierte sogar, als ich die alte PK entfernt hatte, bevor ich merkte, dass es Duplikate gab. +100

159voto

Jon Galloway Punkte 51200

Es gibt einen guten Artikel auf Entfernen von Duplikaten auf der Microsoft Support-Seite. Es ist ziemlich konservativ - sie lassen Sie alles in separaten Schritten machen - aber es sollte gut gegen große Tabellen funktionieren.

Ich habe Self-Joins verwendet, um dies in der Vergangenheit zu tun, obwohl es wahrscheinlich mit einer HAVING-Klausel aufgehübscht 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

0 Stimmen

Perfekt! ich habe festgestellt, dass dies der effizienteste Weg ist, um doppelte Zeilen in meiner alten Mariadb-Version 10.1.xx zu entfernen. danke!

0 Stimmen

Viel einfacher und leichter zu verstehen!

0 Stimmen

Ich habe einen Zweifel, in Ihrem Sql-Abfrage, warum sind Sie nicht mit "From" Schlüsselwort nach "DELETE"? Ich habe von in vielen anderen Lösung gesehen.

103voto

gngolakia Punkte 2126

Die folgende Abfrage ist nützlich, um doppelte Zeilen zu löschen. Die Tabelle in diesem Beispiel hat ID als Identitätsspalte, und die Spalten, die doppelte Daten enthalten, sind Column1 , Column2 y 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) 

Das folgende Skript zeigt die Verwendung von GROUP BY , HAVING , ORDER BY in einer Abfrage und gibt die Ergebnisse mit der doppelten Spalte und ihrer Anzahl zurück.

SELECT YourColumnName,
       COUNT(*) TotalCount
FROM   YourTableName
GROUP  BY YourColumnName
HAVING COUNT(*) > 1
ORDER  BY COUNT(*) DESC

1 Stimmen

MySQL-Fehler mit dem ersten Skript "Sie können die Zieltabelle 'Tabellenname' für die Aktualisierung in der FROM-Klausel nicht angeben".

0 Stimmen

Abgesehen von dem Fehler, den D.Rosado bereits gemeldet hat, ist Ihre erste Abfrage auch sehr langsam. Die entsprechende SELECT-Abfrage dauerte bei mir +- 20 Mal länger als die akzeptierte Antwort.

8 Stimmen

@parvus - Die Frage ist mit SQL Server und nicht mit MySQL gekennzeichnet. Die Syntax ist in SQL Server in Ordnung. Außerdem ist MySQL notorisch schlecht bei der Optimierung von Unterabfragen siehe zum Beispiel hier . Diese Antwort ist in SQL Server in Ordnung. In der Tat NOT IN oft besser abschneidet als OUTER JOIN ... NULL . Ich würde eine HAVING MAX(ID) IS NOT NULL zur Abfrage hinzufügen, auch wenn dies semantisch nicht notwendig sein sollte, da dies den Plan verbessern kann Beispiel dafür hier

76voto

SoftwareGeek Punkte 14446
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

0 Stimmen

Warum eine Postgres-Lösung zu einer SQL Server-Frage posten?

3 Stimmen

@Lankymart Weil auch Postgres-Benutzer hierher kommen. Schauen Sie sich die Punktzahl dieser Antwort an.

2 Stimmen

Ich habe dies in einigen beliebten SQL-Fragen gesehen, z. B. in aquí , aquí y aquí . Der OP hat seine Antwort bekommen und alle anderen haben auch etwas Hilfe bekommen. IMHO kein Problem.

CodeJaeger.com

CodeJaeger ist eine Gemeinschaft für Programmierer, die täglich Hilfe erhalten..
Wir haben viele Inhalte, und Sie können auch Ihre eigenen Fragen stellen oder die Fragen anderer Leute lösen.

Powered by:

X