WernerK: Doppelte, dreifache Einträge löschen

Hallo,
eine SQL Server 2008 Express Datenbank mit einer Tabelle "namenliste" hat zwei Spalten:
"vname" und "nname".
Es sind eigentlich 200 Einträge drin. Vermutlich weil mehrmals ein Import gemacht wurde sind es aber 600. Es kommt alles drei mal vor.

Gibt es eine Delete Möglichkeit die alle doppelten bzw. dreifachen Vorkommen löscht, so das nur noch die "richtigen" 200 (einmaligen) Zeilen vorkommen?

Ich hätte es zur Not etwas umständlich gemacht:
--zusätzliche Spalte mit ID und IDENTITY(1,1) angelegt
--Danach ein Delete nach ID > 200

Es gibt sicher aber noch eine elegentere Lösung?

vielen Dank
Gruss
Werner

  1. Moin,

    Gibt es eine Delete Möglichkeit die alle doppelten bzw. dreifachen Vorkommen löscht, so das nur noch die "richtigen" 200 (einmaligen) Zeilen vorkommen?

    Wenn es wirklich identische Datensätze doppelt gibt, warum selektierst du nicht DISTINCT, sicherst diese Datensätze (die dann eindeutig sind), löschst die Tabelle und importierst das vorher gesicherte Ergebnis?

    Mit "sichern" meine ich entweder eine extra für diesen Zweck angelegte Tabelle, oder ein beliebiges Dateiformat, welches sich einfach wieder importieren lässt.

    Grüße Marco

    --
    Ich spreche Spaghetticode - fließend.
    1. Hallo Marco,

      Wenn es wirklich identische Datensätze doppelt gibt, warum selektierst du nicht DISTINCT, sicherst diese Datensätze (die dann eindeutig sind), löschst die Tabelle und importierst das vorher gesicherte Ergebnis?

      Ja gut, diese Variante ist auch möglich.
      Mir ging es mit meiner Frage eigentlich nur darum, ob man mit einem (oder mehreren) SQL Befehlen dieses Problem lösen könnte ohne mit temporären Tabellen oder zusätzlichen Spalten etc. zu arbeiten?

      Gruss
      Werner

      1. Tach!

        Mir ging es mit meiner Frage eigentlich nur darum, ob man mit einem (oder mehreren) SQL Befehlen dieses Problem lösen könnte ohne mit temporären Tabellen oder zusätzlichen Spalten etc. zu arbeiten?

        Du kannst mit einem Self-Join alle doppelten Datensätze finden. Das sind die, bei denen die entsprechenden fachlichen Werte übereinstimmen, aber die ID eine andere ist. Die kannst du nun aber nicht alle auf einmal löschen, weil dann keiner mehr übrigbleibt. Das Problem ist auch nicht neu und schon mehrfach beantwortet. Ich merk mir nur nie, wie es geht, weswegen ich dich bitte, im Archiv nach den Lösungsvorschlägen zu suchen. Wenn du über die gefundenen Lösungen sprechen möchtest, kannt du das dann gern hier tun.

        dedlfix.

        1. Hallo,

          ich habe mal im Archiv gestöbert.
          Ich komme wohl nicht drum herum eine zusätzliche Spalte mit Identity und Primary Key anzulegen.

          Ich habe diese Lösung gefunden, die aber bei mir nicht funktioniert.

          DELETE  
          FROM  
           tabelle  
          WHERE  
           (  
           tabelle_id NOT IN  
            (  
            SELECT  
             Temp.tabelle_id  
            FROM  
             (  
             SELECT DISTINT  
              tabelle_id,  
              tabelle_beispieldatenfeld       -- das Dublettenkritium, können auch mehrere sein  
             FROM  
              tabelle  
             ) Temp  
            )  
           )
          

          Ich habe also eine Spalte "namenid" angelegt, als Primary mit Identity
          Schon mit den einfachen Select Distinct Befehl komme ich nicht weiter , weil ein
          Select Distinct nname from namenliste
          bringt zwar nur die gewünschten 200 Einträge. Aber ich bräuchte ja eine namenid um mit Subselect unf NOT In weiter zu arbeiten.

          Gruss
          Werner

          1. Hallo
            nun habe ich doch noch eine Lösung gefunden.

            Für diejenigen die es interessiert:

            Delete
            FROM [myTable]
            WHERE id NOT IN
            (
            SELECT MAX(id)
            FROM [myTable]
            GROUP BY name)

            Gruss
            Werner

            1. Meine Herren,

              Für diejenigen die es interessiert:

              Delete
              FROM [myTable]
              WHERE id NOT IN
              (
              SELECT MAX(id)
              FROM [myTable]
              GROUP BY name)

              Das löscht alle bis auf einen User mit dem selben Nachnamen. Unterschiedliche Vornamen werden einfach ignoriert.

              1. Hallo

                Das löscht alle bis auf einen User mit dem selben Nachnamen. Unterschiedliche Vornamen werden einfach ignoriert.

                Das ist schon klar. Ich ging in meinem Beispiel auch davon aus (siehe Eingangspost) das beide Spalten genau identisch sind, weil vermutlich 2-3 mal ein Datenimport gemacht wurde.

                Auf jedenfall hat es bei mir funktioniert so wie ich es wollte.

                Gruss
                Werner

                1. Meine Herren,

                  Hallo

                  Das löscht alle bis auf einen User mit dem selben Nachnamen. Unterschiedliche Vornamen werden einfach ignoriert.

                  Das ist schon klar. Ich ging in meinem Beispiel auch davon aus (siehe Eingangspost) das beide Spalten genau identisch sind

                  Du gehst davon aus das vname = nname ist? Das kann ich deinem Eingangspost nicht entnehmen und kann mir auch nicht vorstellen, dass du das wirklich meinst. Um das Problem nochmal zu verdeutlichen:

                  1 Tina Müller  
                  2 Tina Müller  
                  3 Brigitte Müller
                  

                  Wird nach deiner Abfrage zu:

                  3 Brigitte Müller  
                  
                  

                  Schade für Tina.

                  --
                  Hey Girl,
                  i wish you were asynchronous, so you'd give me a callback.
                  1. Hallo,

                    Du gehst davon aus das vname = nname ist? Das kann ich deinem Eingangspost nicht entnehmen und kann mir auch nicht vorstellen, dass du das wirklich meinst. Um das Problem nochmal zu verdeutlichen:

                    Habe ich mich wirklich so ausgedrückt?
                    Also, um es nochmals deutlich zu machen.

                    Meine Tabelle sah urspünglich wirklich so aus, mit identischen Zeile

                    1 Tina Müller
                    2 Tina Müller
                    3 Tina Müller

                    Wie gesagt, das Problem bestand weil es kein Unique Constraint gab und weil jemand aus einer anderen DB mehrmals die gleichen Daten importiert hat.

                    Gruss
                    Werner

                    1. Meine Herren,

                      Wie gesagt, das Problem bestand weil es kein Unique Constraint gab und weil jemand aus einer anderen DB mehrmals die gleichen Daten importiert hat.

                      Das Problem habe ich begriffen, ich wollte dich nur auf einen Fehler in deiner Lösung aufmerksam machen.

                      In deiner Abfrage gruppierst du Datensätze anhand des Feldes "name" (was ich übrigens für einen Typo von dir halte, ich deute es mal als "nname"). Das heißt es werden alle Datensätze mit dem selben Nachnamen gruppiert, auch wenn der Vorname sich unterscheidet. Anschließend löschst du alle Datensätze aus dieser Gruppe bis auf denjenigen mit der höchsten ID. Dadurch können Datensätze fälschlicherweise verloren gehen, sowie ich es dir in dem Beispiel aufgezeigt habe.

                      --
                      Hey Girl,
                      i wish you were asynchronous, so you'd give me a callback.
            2. Tach!

              nun habe ich doch noch eine Lösung gefunden.

              Übrigens, die erste Lösung, die du fandest, war von jemandem, der nicht gerade für fachliche Kompetenz bekannt war. Jedenfalls, wenn beim Abfragen mit DISTINCT auch die (eindeutige) ID in der Ergebnismenge ist, dann können keine doppelten Datensätze gefunden werden. Um Dopplungen zu finden kann man nur gruppieren und zählen oder das schon erwähnte Self-Joinen verwenden.

              Für diejenigen die es interessiert:
              Delete
              FROM [myTable]
              WHERE id NOT IN
              (
              SELECT MAX(id)
              FROM [myTable]
              GROUP BY name)

              Das setzt voraus, dass wirklich jeder Datensatz doppelt enthalten ist (oder dreifach oder vierfach - dann muss man es mehrfach ausführen, um auf einfach zu kommen). Ansonsten findet das MAX(id) auch einen nur einzeln vorhandenen Datensatz. Für deinen Fall mag das genau passend sein, ich erwähn das nur mal, falls jemand mit einem anders gelagerten Fall diese Lösung findet.

              dedlfix.

              1. Moin,

                Übrigens, die erste Lösung, die du fandest, war von jemandem, der nicht gerade für fachliche Kompetenz bekannt war. Jedenfalls, wenn beim Abfragen mit DISTINCT auch die (eindeutige) ID in der Ergebnismenge ist, dann können keine doppelten Datensätze gefunden werden.

                Sein Ausgangsposting beschrieb eindeutig, dass die Tabelle nur 2 Spalten hat, ohne ID oder sonstiges eindeutiges Merkmal; dort wäre die DISTINCT-Methode möglich gewesen.

                Grüße Marco

                --
                Ich spreche Spaghetticode - fließend.
                1. Tach!

                  Übrigens, die erste Lösung, die du fandest, war von jemandem, der nicht gerade für fachliche Kompetenz bekannt war. Jedenfalls, wenn beim Abfragen mit DISTINCT auch die (eindeutige) ID in der Ergebnismenge ist, dann können keine doppelten Datensätze gefunden werden.
                  Sein Ausgangsposting beschrieb eindeutig, dass die Tabelle nur 2 Spalten hat, ohne ID oder sonstiges eindeutiges Merkmal; dort wäre die DISTINCT-Methode möglich gewesen.

                  Da hast du Recht. Dass da kein Index in seiner ursprünglichen Tabelle war, hatte ich nicht richtig mitbekommen. Das ist vermutlich ein weniger häufig vorkommender Fall. Da hilft meines Erachtens nur deine Variante mit dem temporären Erzeugen einer DISTINCT-Tabelle. Also zumindest wenn es effizient gehen soll. Da man keinen richtigen Anfasser (eine ID) hat, kann man einen doppelten Datensatz nur löschen, indem man einzeln alle Feldinhalte in die WHERE-Klausel schreibt und mit LIMIT 1 den Löschvorgang einschränkt (oder TOP 1 bei MS-SQL). Und das wird dann aufwendig wegen der vielen Einzel-Statements.

                  Dann war die Frage ja nach der allgemeinen Vorgehensweise, und da ist wohl eher üblich, eine Tabelle mit Primärschlüssel zu haben. Man muss da in irgendeiner Weise die IDs der überflüssigen Datensätze ermitteln, die man dann dem DELETE zum Fraß vorwerfen kann. Mit DISTINCT (wie im gezeigten Code des Archivpostings) kann man da nicht arbeiten, weil man so nicht die Dopplungen zusammenfassen kann, ohne die ID unberücksichtigt zu lassen. Aber man kann GROUP BY und MIN(id) oder MAX(id) nehmen - wenn man numerische IDs hat. Hat man Datensätze mehr als doppelt, muss man das Löschen solange wiederholen, bis keine Datensätze mehr gelöscht werden konnten.

                  dedlfix.