Announcement

Collapse
No announcement yet.

MS SQL (Access-Datenbank) doppelte Einträge vermeiden

Collapse
X
  • Filter
  • Time
  • Show
Clear All
new posts

  • MS SQL (Access-Datenbank) doppelte Einträge vermeiden

    Hallo,

    ich habe ein spezielles Problem, da es in MS Access SQL kein INSERT IGNORE gibt und in diesem Fall auch kein Primärkey weiterhilft. Am besten, ich beschreibe die Ausgangslage mit vereinfachten Tabellen:

    Tabelle i: ind, nam -- das sollen Einzelpersonen sein
    Tabelle f: fam, h, w -- stellt eine "Familie" dar, h+w sind "Vater" und "Mutter" von
    Tabelle r: fam, c -- Kinder c in Familie fam.

    In einem Visual C# Programm schreibe ich nun zunächst eine der Personen aus Tabelle i in eine Tabelle Temp. Dann werden in einer Schleife die früheren Generationen durchsucht und so Eltern, Großeltern, Urgroßeltern in Temp geschrieben:

    Für die Eltern:

    INSERT INTO Temp ( ind, fam, gen, nam )
    SELECT i.ind, f.fam, -1, i.nam
    FROM i, r, f, Temp AS t
    WHERE (i.ind=f.h OR i.ind=f.w) AND f.fam=r.fam AND r.c=t.ind AND t.gen=0;

    Für die Großeltern:

    INSERT INTO Temp ( ind, fam, gen, nam )
    SELECT i.ind, f.fam, -2, i.nam
    FROM i, r, f, Temp AS t
    WHERE (i.ind=f.h OR i.ind=f.w) AND f.fam=r.fam AND r.c=t.ind AND t.gen=-1;

    und so weiter (Zahlen natürlich als Variablen, mit DO...WHILE (written>0), bis keine Vorfahren mehr in den Tabellen sind.

    Funktioniert auch alles wunderbar, nur... es kommt vor, dass Geschwister von Vorfahren auftauchen, manche mehrfach heiraten - sprich, Einträge doppelt, vierfach usw. geschrieben werden. Idee war:

    INSERT INTO Temp ( ind, fam, gen, nam )
    SELECT i.ind, f.fam, -2, i.nam
    FROM i, r, f, Temp AS t
    WHERE (i.ind=f.h OR i.ind=f.w) AND f.fam=r.fam AND r.c=t.ind AND t.gen=-1
    AND NOT IN (SELECT 1 FROM Temp AS x WHERE x.ind=i.ind AND x.fam=f.fam AND x.gen=-2);

    für die 2. Generation, die anderen entsprechend - es nutzt nichts! Primärkey über ind, fam, gen nützt nichts, weil ab der SQL-Anweisung, in der ein Dupkey vorkommt, gar nichts mehr geschrieben wird.

    Aber eigentlich sollte der Subselect doch gehen - wo steckt der Fehler???
    Oder geht alles viel viel einfacher??? Stehe ich mit beiden Beinen fest auf dem Schlauch?

    Danke

    Josef







  • #2
    Finde es schon seltsam Usern hier Tabellen und SQLs vorzusetzen die so sprechende Namen wie i,r,f,x haben.
    Damit kann man sich prima in das Problem reindenken.

    Warum setzt du den SQL

    SELECT i.ind, f.fam, -2, i.nam
    FROM i, r, f, Temp AS t
    WHERE (i.ind=f.h OR i.ind=f.w) AND f.fam=r.fam AND r.c=t.ind AND t.gen=-1
    AND NOT IN (SELECT 1 FROM Temp AS x WHERE x.ind=i.ind AND x.fam=f.fam AND x.gen=-2);

    nicht direkt ab und siehst welche unerwünschten Personen drin sind und aus welchem Grunde sie nicht vom SQl erwischt wurden.
    Konnte mir noch vorstellen, dass AND x.gen=-2 raus muss oder geändert in größer oder kleiner; sonst muss eine Person genau in dieser Generation da sein
    Christian

    Comment


    • #3
      danke, Christian,

      ich bin 66 und nicht mit ellenlangen sprechenden Namen sondern mit platzsparenden Abkürzungen aufgewachsen. Aber natürlich haben die realen Tabellen in meiner Datenbank "echte" Namen wie Individuals, Families, [References] usw., aber ich fand es der Deutlichkeit halber besser, statt

      FROM Individuals AS i, Families AS f, [References] AS r

      die Tabellen im Beispiel gleich i, f und r zu nennen.

      Natürlich prüfe ich die einzelnen Abfragen in Access, bevor ich sie als Command in VS C# einbaue.

      Mit t.gen=-1 erwische ich alle Personen in Temp der Generation -1 (Eltern) und schreibe mit -2 deren Eltern, also die Großeltern rein. In diesem Fall sollen die Großeltern nicht doppelt vorkommen, es also nur jeweils 1 Satz mit "ind, fam, -2" in Temp geben.

      Bei den ollen Ägyptern konnten schon mal Bruder und Schwester heiraten, bei uns kommt das eher selten vor, daher bei -1 oder -2 eher nicht. Aber wenn irgendwann mal Großnichten und -neffen geheiratet haben, taucht das Problem bei gen=-4 oder früher auf. Ich bekomme in dem aktuell von mir benutzten Beispiel 239 Einträge in Temp bis zu gen=-11, von denen 37 doppelt bis vierfach sind. Die kann ich natürlich vor der weiteren Verarbeitung rauslöschen, aber sinnvoller wäre natürlich, sie gar nicht reinzuschreiben.

      Comment


      • #4
        Allgemein um doppelte Datensätze zu finden:

        SELECT
        KritFeld1,
        KritFeld2,
        KritFeld3,
        ...,
        COUNT(*)
        FROM Tabelle
        GROUP BY KritFeld1, KritFeld2, KritFeld3, ...
        HAVING COUNT(*) > 1

        Irgendwie scheint es dann doch an der "gen" zu liegen.
        Tja, du bist nicht der einzige mit 6x Lebensjahren....
        Christian

        Comment


        • #5
          Hallo Christian,

          o-O dein Tipp ist der, den MS auch empfiehlt um doppelte Sätze zu finden. Nur: die soll ich dann manuell rauslöschen, nach der Liste, die dann rauskommt!

          Ja, die von mir genannten 37 Einträge finde ich genau mit dieser Abfrage, soweit war ich schon:

          SELECT ind, fam, gen, count(*)
          FROM Temp
          GROUP BY ind, fam, gen
          HAVING count(*)>1;

          aber ich will sie ja gar nicht erst reinschreiben! Ich versuche mal ein Bild anzuhängen - er sagt mein Profil erlaubt das nicht? Hier der Link: http://www.sternwarte-wuerzburg.de/images/Baum.jpg

          Wenn das Programm dir letzte (rechte) Spalte abarbeitet, findet das SQL diese 16 Einträge in Temp, dazu von den letzten 14 Personen 14 Väter und 14 Mütter, von denen aber je 2 der "Eichfelder" doppelt vorkommen. Die sollen nur 1x geschrieben werden. Vermutlich funktioniert das deswegen nicht, weil SQL vorher prüft, ob die NOT IN Bedingung erfüllt ist (ja, ist sie), und nicht on the fly prüft. Es werden alle Sätze auf 1x eingefügt. Daher passiert auch gar nichts, wenn ich auf die 3 Felder einen Primärkey setze, denn das Einsetzen von 2 identischen Sätzen verletzt diese bedingung, daher wird gar nichts geschrieben, nur eine fehlermeldung ausgeworfen.


          Comment


          • #6
            Würde ja versuchen das select mit dem suchen der Doppelten als subselect zu nutzen....
            where ID not in (subselect.....)
            Christian

            Comment


            • #7
              Hallo Christian,

              ich habs, es ist so einfach, und warum bin ich nicht gleich drauf gekommen:

              Für die Eltern:

              INSERT INTO Temp ( ind, fam, gen, nam )
              SELECT DISTINCT i.ind, f.fam, -1, i.nam
              FROM i, r, f, Temp AS t
              WHERE (i.ind=f.h OR i.ind=f.w) AND f.fam=r.fam AND r.c=t.ind AND t.gen=0;

              usw. !!!!!!!!!!!!!!!!!!!!!!!!

              Comment

              Working...
              X