Doppelte Datensätze - untenstehende Artikel

Bevor ich zu jedem der untenstehenden Artikel Einzelkommentare dazuschreibe:

  1. Will man doppelte Datensätze löschen, so sind alle Zeilen herauszufinden, deren Werte mit Ausnahme der ID übereinstimmen. Das geht mit:

    Select Spalte1, Spalte2, Spalte3
    From Tabelle
    Group By Spalte1, Spalte2, Spalte3
    Having Count(*) > 1

  2. Von diesen Zeilen muß man willkürlich eine auswählen, die erhalten bleiben soll, von dieser benötigt man die Id. Also kombiniert man das mit der oberen Abfrage als Join:

    Select Min(A.Id) As Id_soll_dableiben
    From Tabelle As A Inner Join
    (Select X.Spalte1, X.Spalte2, X.Spalte3
    From Tabelle As X
    Group By X.Spalte1, X.Spalte2, X.Spalte3
    Having Count(*) > 1) As B
    On A.Spalte1 = B.Spalte1 And A.Spalte2 = B.Spalte2
    And A.Spalte3 = B.Spalte3
    Group By A.Spalte1, A.Spalte2, A.Spalte3

  3. Nun kann man alle Datensätze löschen, die mehrfach vorkommen, also in der ersten Menge enthalten sind und nicht in der zweiten Menge drin sind:

    Delete From Tabelle

    – Zum Test: Select * From Tabelle

    Where Id In

    – Das wählt alle Ids aus, bei denen die Inhalte
    – mehrfach sind

    (Select A.Id As Id_soll_weg
    From Tabelle As A Inner Join
    (Select X.Spalte1, X.Spalte2, X.Spalte3
    From Tabelle As X
    Group By X.Spalte1, X.Spalte2, X.Spalte3
    Having Count(*) > 1) As B
    ON A.Spalte1 = B.Spalte1 And A.Spalte2 = B.Spalte2
    And A.Spalte3 = B.Spalte3)

    And Id Not In

    – Das wählt willkürlich die minimale Id

    (Select Min(B.Id) As Id_soll_bleiben
    From Tabelle As B Inner Join
    (Select X.Spalte1, X.Spalte2, X.Spalte3
    From Tabelle As X
    Group By X.Spalte1, X.Spalte2, X.Spalte3
    Having Count(*) > 1) As C
    On B.Spalte1 = C.Spalte1 And B.Spalte2 = C.Spalte2
    And B.Spalte3 = C.Spalte3
    Group By B.Spalte1, B.Spalte2, B.Spalte3)

Für einen Test macht man aus dem letzten Delete ein Select und kontrolliert das Ergebnis. Es gibt auch noch kompaktere Möglichkeiten, aber ich habe das Problem lieber zerlegt.


Gruß, Jürgen Auer

Kleine Ergänzung: Das bisherige Beispiel stimmt, falls alle Zellen belegt sind. Sind Zellen NULL, so werden diese nicht mit berücksichtigt, weil der INNER JOIN - Vergleich false liefert. Um diesen Fall mit einzubeziehen, ersetzt man in den Unterabfragen die ‚großen INNER JOIN‘ durch LEFT JOIN. Dann liefert sowohl die Id_soll_weg- als auch die Id_soll_bleiben-Abfrage auch alle einmalig vorkommenden Zeilen, so daß diese mit drinbleiben.


Gruß, Jürgen Auer

spitzenmäßige Antwort!!!
Hallo Jürgen,
absolut spitzenmäßig! Hab das mal ausgetestet. Funktioniert einwandfrei. Bin begeistert.
Gruß Markus

[Bei dieser Antwort wurde das Vollzitat nachträglich automatisiert entfernt]

Leider iss mir noch eine kleine Ungenauigkeit unterlaufen, die allerdings nicht tragisch ist:

Will man die Null-Werte berücksichtigen, muß man aus dem Inner einen Left Join machen. Damit erwischt der Teil, der die zu löschenden Datensätze ermittelt, jedoch alle Zeilen, auch die, die nur einmal vorkommen. Die einmaligen zu erhaltenden werden in der 'Erhaltungsabfrage (Min(id)) ebenfalls erwischt, damit gleicht sich das wieder aus. Damit läßt sich in dieser die dortige Unterabfrage entfernen - man ermittelt einfach zu jeder Datenkombination die minimale ID. Ergebnis: Man kann den zu löschenden Abschnitt gleich weglassen und den anderen vereinfachen. Ich hatte die Details etwas ausführlicher gemacht, um zu klären, wie sich die Lösung zusammenbaut. Das Ergebnis ist dann hübsch übersichtlich. Der Vollständigkeit halber:

Delete From Tabelle 


-- Zum Test: Select \* From Tabelle


Where Id Not In 

 -- Das wählt willkürlich die minimale Id über alle Kombinationen

 (Select Min(B.Id) As Id\_soll\_bleiben

 From Tabelle As B 

 Group By B.Spalte1, B.Spalte2, B.Spalte3)

Gruß, Jürgen Auer

noch besser!
danke jürgen!

[Bei dieser Antwort wurde das Vollzitat nachträglich automatisiert entfernt]