Update aller FKs die in der Mastertabelle gelöscht werden sollen

lapadula

Aktiver Benutzer
Beiträge
33
Hallo ich bräuchte Hilfe bei dem folgenden Updatebefehl:

Ich möchte aus Tabelle A alle doppelten Einträge löschen

DELETE FROM A
WHERE ID NOT IN
(
SELECT Min(ID) FROM A GROUP BY Schluessel
)

Beispiel:
ID | Schluessel
-------------------
1 | SchluesselA
2 | SchluesselA
3 | SchluesselA

damit würde nur ein Schlüssel A bleiben.

Das Problem ist nun, dass die ID aus Tabelle A in Tabelle B veknüpft ist.

Nun müssen in der Tabelle B alle Einträge die in der Tabelle A gelöscht werden auf die ID 1 gesetzt werden.

Beispiel Tabelle B:

Vorher:
ID | TabelleA_ID
------------------
1 | 1
2 | 2
3 | 3

Nachher:
ID | TabelleA_ID
------------------
1 | 1 (SchluesselA)
2 | 1 (SchluesselA)
3 | 1 (SchluesselA)

Wie stelle ich das an?
 
Werbung:
Du schreibst im ersten Schritt die Fremdschlüssel in Tabelle B die auf Tabelle A verweisen um, ein entsprechender Foreign Key Constraint würde das auch hervorragend überwachen. Du könntest nicht löschen solange die FKs nicht neu gesetzt wurden und noch Einträge auf die zu löschenden Datensätze in A verweisen.

Außerdem solltest du deine Lösch-Bedingung verfeinern. So werden ja alle Einträge bis auf einer gelöscht, das ist vermutlich nicht dein Ziel oder?
 
Doch das ist mein Ziel gewesen. Von drei Einträgen soll nur einer überig bleiben und dieser soll dann auf alle Einträge aus Tabelle B zeigen die in Tabelle A gelöscht wurden.
Hoffe das ist verständlich.

Ich habe das nun einfach mit nem kleinen Hilfstools getan:

Code:
private void Start()
        {
            List<Datensatz> listDatensatz = ReadDocument();

            var group = listDatensatz.GroupBy(x => x.Schluessel).ToList();

            foreach (var g in group)
            {
                var listDatenSatzPaket = g.ToList();

                var keep = listDatenSatzPaket.FindAll(x => x.RowNumer == 1).FirstOrDefault();
                var listUpdate = listDatenSatzPaket.FindAll(x => x.RowNumer >= 2);

                foreach (Datensatz datensatz in listUpdate)
                {
                    var Command = Update tbl_B set tbl_A_ID = " keep.ID " WHERE tbl_A_ID = " + datensatz.ID.ToString();
                    //var Command = "DELETE FROM tbl_A where ID = datensatz.ID;
                  
                    executeCommand(Command);
                }
            }


        }

Ich habe zuerst mit einer SQL-Abfrage alle doppelten Einträge rausgeholt und diese mit RowNumber nummeriert.

Code:
   SELECT
         Schluessel, ID,
         ROW_NUMBER() OVER (PARTITION BY Schluessel ORDER BY id) AS intRow
     FROM tbl_A

Die Liste sah dann ungefährt so aus:

Schluesse | ID | rowNumber
0001 | 32 | 1
0001 | 4 | 2
0001 | 64 | 3
0002 | 54 | 1
0002 | 2 | 2
0002 | 6 | 3

Diese Liste lese ich ein, packe das in das Objekt Datensatz und Gruppiere das ganze.

Gruppe1:
0001 | 32 | 1
0001 | 4 | 2
0001 | 64 | 3

Gruppe2:
0002 | 54 | 1
0002 | 2 | 2
0002 | 6 | 3

Der Datensatz mit RowNumber 1 soll bleiben, der Rest soll verschwinden.
Zuerst werden in Tabelle B alle FKs auf die ID mit der RowNumber 1 gesetzt. Also Update tbl_B set tbl_A_ID = 32 where tbl_A_ID = 4 or tbl_A_ID = 64.
Im nächsten Schritt werden aus Tabelle A alle Eintäge mit der RowNumer Größer 1 gelöscht => 4 und 64.
 
Ja von 3 Datensätzen bleibt einer übrig aber mit dem Code aus Post #1 bleibt eben von 3 Mio Datensätzen auch nur einer übrig, es ist also sehr wohl etwas komplexer.

Funktioniert denn dein Code?

Einfacher aktuallisieren läßt sich das auch so:
Code:
UPDATE   TabelleB
SET       TabelleB.TabelleA_ID = t2.ID
FROM   TabelleB
INNER JOIN TabelleA t1
ON       TabelleB.TabelleA_ID = t1.ID
INNER JOIN (   SELECT   min(ID) AS ID,
                       Schluessel
               FROM   TabelleA
               GROUP BY Schluessel ) t2
ON       t1.Schluessel = t2.Schluessel

PS: Mit ROW_NUMBER() kann man natürlich auch hier arbeiten...

Beim Löschen ist Vorsicht geboten, eigentlich geht:
Code:
DELETE
FROM   TabelleA
WHERE   ID NOT IN (   SELECT   TabelleA_ID
                   FROM   TabelleB
                   WHERE   TabelleA_ID IS NOT NULL )
Das würde aber auch einmalige Schluessel löschen die einfach nicht durch TabelleB referenziert werden. Wenn das vorkommen kann muss man das noch abfangen.
 
Okay das war mit nicht bewusst, gut das dieser Befehl nicht durchging :D
Mein Code hat soweit funktioniert, ist nur nicht so elegant programmiert, soll auch nur eine einmalige Sache sein.

Aber ich speichere mir deinen Vorschlag auch mal weg, danke dafür. Vllt kommt das iwann nochmal vor.
 
Werbung:
In diesem Fall empfiehlt es sich definitiv Foreign Keys wirklich als Constraint zu setzen so das beim Löschen gemeckert wird wenn zuviel betroffen ist.
 
Zurück
Oben