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.

20voto

James Errico Punkte 4966

Ich bevorzuge die Unterabfrage \having count(*) > 1 Lösung für die innere Verknüpfung, weil ich sie leichter zu lesen fand und sie sehr einfach in eine SELECT-Anweisung umzuwandeln war, 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
--)

0 Stimmen

Werden dabei nicht alle Datensätze gelöscht, die in der inneren Abfrage auftauchen? Wir müssen nur Duplikate entfernen und das Original erhalten.

3 Stimmen

Sie geben nur die Datei mit der niedrigsten ID zurück, basierend auf der min(id) in der Select-Klausel.

0 Stimmen

Ja, aber die Frage bezog sich nicht darauf, wie die zu löschenden Zeilen zurückgegeben werden können, sondern darauf, wie die doppelten Zeilen gelöscht werden können. Können Sie erläutern, wie ich die Zeilen löschen kann, die die Abfrage zurückgegeben hat?

17voto

heta77 Punkte 179
SELECT  DISTINCT *
      INTO tempdb.dbo.tmpTable
FROM myTable

TRUNCATE TABLE myTable
INSERT INTO myTable SELECT * FROM tempdb.dbo.tmpTable
DROP TABLE tempdb.dbo.tmpTable

5 Stimmen

Das Kürzen wird nicht funktionieren, wenn Sie Fremdschlüsselverweise auf myTable haben.

15voto

Ruben Verschueren Punkte 812

Ich dachte, ich teile meine Lösung mit, da sie unter besonderen Umständen funktioniert. In meinem Fall hatte die Tabelle mit den doppelten Werten keinen Fremdschlüssel (weil die Werte aus 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, die nicht nur sicherstellt, dass alles als Ganzes ausgeführt wird, sondern mir auch erlaubt, zu testen, ohne etwas zu riskieren. Aber natürlich sollte man trotzdem ein Backup machen, nur um sicher zu gehen...

14voto

Ostati Punkte 4377

CTE verwenden. Die Idee besteht darin, eine oder mehrere Spalten zu verbinden, die einen doppelten Datensatz bilden, und dann zu entfernen, was immer Sie wollen:

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

1 Stimmen

Ich glaube, Sie vermissen ein AND in Ihrem JOIN.

14voto

Draško Punkte 707

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

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

er löschte 1M Zeilen in etwas mehr als 30sec aus einer Tabelle mit 2M (50% Duplikate)

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