Sven: Doppelte Einträge anzeigen/entfernen?

Hallo,

wir haben hier eine Email Datenbank in MySQL. Leider haben wir erst zu spät das Email Feld als Unique definiert und nun sind jede Menge doppelte Emailadressen in der DB.

Was ich nun suche ist ein Request, der mir nur die doppelten Dateneinträge zeigt. Und dann wäre noch ein Request gut, der automatisch bei allen doppelten Einträgen alle bis auf einen Eintrag löscht.

Kann mir da jemand von Euch weiterhelfen? Ich kenne mich mit SQl leider Null aus...

Danke und einen schönen (Sommer?)tag
Sven

  1. hi,

    Was ich nun suche ist ein Request, der mir nur die doppelten Dateneinträge zeigt.

    COUNT() in verbindung mit GROUP BY sollte weiterhelfen; in der WHERE-klausel auf > 1 abfragen.

    Und dann wäre noch ein Request gut, der automatisch bei allen doppelten Einträgen alle bis auf einen Eintrag löscht.

    ob das mit SQL-mitteln möglich ist, weiß ich nicht.
    da wäre dann vielleicht ein script angebracht, welches die ergebnisse obiger abfrage dazu benutzt, einzeln zu löschen.

    gruß,
    wahsaga

    --
    /voodoo.css:
    #GeorgeWBush { position:absolute; bottom:-6ft; }
    1. Danke.

      Auch auf die Gefahr hin, dass Ihr mich als Unwissenden verschreit, mir ist das noch zuwenig Information. Hast Du es vielleicht ein wenig konkreter?

      Ich bekomme einfach nur Fehler, weil ich nicht fit bin mit SQL

      Danke,
      Sven

      1. Danke.

        Auch auf die Gefahr hin, dass Ihr mich als Unwissenden verschreit, mir ist das noch zuwenig Information. Hast Du es vielleicht ein wenig konkreter?

        Ich bekomme einfach nur Fehler, weil ich nicht fit bin mit SQL

        Danke,
        Sven

        probiers doch mal mit SELECT DISTINCT ...

        dann bekommst du keine doppelten datensätze
        --> könntest die ja dann kopieren, und in ne neue tabelle einfügen, alte Tabelle löschen...

        1. Du bräuchtest sowas wie

          SELECT adr, count(DISTINCT adr) AS c FROM email WHERE 1<c;

          Nur ich glaube sowas ist in mySQL nicht möglich, da mySQL in der WHERE-Abfrage keine Formeln zulässt (und auch kein Having und SubQueries).

          Was möglich ist...

          SELECT adr, count(DISTINCT adr) AS c FROM email ORDER BY c DESC LIMIT 1;

          Diese Abfrage liefert ein Ergebniss mit zwei Werten zurück...
          Einen davon löschen und dann solange die Abfrage durchführen, bis c = 1 ist.

          1. echo $begrüßung;

            SELECT adr, count(DISTINCT adr) AS c FROM email WHERE 1<c;

            Nur ich glaube sowas ist in mySQL nicht möglich, da mySQL in der WHERE-Abfrage keine Formeln zulässt (und auch kein Having und SubQueries).

            Der erste Teil stimmt, die Begründung (und das in den Klammern) stimmt nicht.
            Alias-Namen (c) sind in der WHERE-Klausel nicht zulässig. Stattdessen count(...) hinzuschreiben wird abgelehnt, weil es eine Gruppierfunktion ist. "Normale" Funktionen lassen sich ohne Gegenwehr von MySQL in der WHERE-Klausel verwenden.
            HAVING gibt es in MySQL und Subqueries wurden mit Version 4.1 eingeführt.

            SELECT adr, count(DISTINCT adr) AS c FROM email ORDER BY c DESC LIMIT 1;

            Diese Abfrage liefert ein Ergebniss mit zwei Werten zurück...

            Nein, da fehlt ein GROUP BY, count(...) mag sonst nicht.

            echo "$verabschiedung $name";

            1. Wo er recht hat hat er recht,

              aber wie wär's mal mit einer etwas wilderen Lösung ?

              SELECT m1.id FROM adresse m1, adresse m2 WHERE m1.adr=m2.adr AND m1.id != m2.id

              Liefert alle Datensätze zurück, bei denen ein zweiter Datensatz existiert mit gleicher Adresse.

              Setzt aber vorraus, daß es einen eindeutigen Schlüssel (PK) gibt, ich habe ihn hier mal id genannt

              1. echo $begrüßung;

                aber wie wär's mal mit einer etwas wilderen Lösung ?

                SELECT m1.id FROM adresse m1, adresse m2 WHERE m1.adr=m2.adr AND m1.id != m2.id

                Das sieht recht elegant aus und tut aber leider nicht ganz wie gewünscht. Zum einen sollte noch ein DISTINCT zwischen SELECT und m1.id sonst gibt es bei mehr als 2 gleichen zu viele Ergebnisse. Zum anderen gibt das _alle_ doppelten aus. Wenn davon einer übrig bleiben soll muss der noch irgendwie ausgespart werden.

                Ich glaube, mich auch jetzt zu erinnern, dass vor nicht all zu vielen Monden so eine ähnliche Lösung schon mal diskutiert wurde. Da war noch was mit gruppiert über adr und max(id) oder min(id) ausschließen.

                echo "$verabschiedung $name";

    2. echo $begrüßung;

      Was ich nun suche ist ein Request, der mir nur die doppelten Dateneinträge zeigt.

      COUNT() in verbindung mit GROUP BY sollte weiterhelfen; in der WHERE-klausel auf > 1 abfragen.

      WHERE dürfte noch zu früh sein, HAVING sollte es tun.

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

      Und dann wäre noch ein Request gut, der automatisch bei allen doppelten Einträgen alle bis auf einen Eintrag löscht.

      ob das mit SQL-mitteln möglich ist, weiß ich nicht.
      da wäre dann vielleicht ein script angebracht, welches die ergebnisse obiger abfrage dazu benutzt, einzeln zu löschen.

      Mit SQL und Script geht es beispielsweise so (Pseudocode):

      while (num_rows('SELECT COUNT(*) FROM tabelle GROUP BY email HAVING COUNT(*) > 1')) {

      CREATE TEMPORARY TABLE tmp SELECT id FROM tabelle GROUP BY email HAVING count(*) > 1
        DELETE tabelle FROM tabelle,tmp WHERE tabelle.id = tmp.id
        DROP TABLE tmp

      }

      Die temporäre Tabelle wird pro mehrfacher Email-Adresse mit der id eines der Datensätze angelegt. Also so:

      id email
      1  A
      2  A
      3  B
      4  C
      5  C
      6  C

      Der erste Durchlauf legt für A entweder ID 1 oder 2 und für C entweder 4, 5 oder 6 in die Temp-Tabelle. Im zweiten Durchlauf hat A ist A nur noch einmal vorhanden und wird nicht weiter beachtet, aber von C existierten noch zwei IDs aus 4, 5 und 6, wovon wieder eine beliebige in tmp landet.

      echo "$verabschiedung $name";