Löschen von Datensätzen einer n:m Beziehung

Hallo.
Ich habe folgendes Problem:

Modell:

  • Wir haben 3 Tabellen: a, aXb, b
  • Beziehung a:aXb (1:n) ; b:aXb (1:n) (also in aXb sind Fremdschlüssel von a und b pro Datensatz enthalten).
    [a] -1-----n-[aXb]-n-----1-[b]

Vorhaben:
Ich will einen Teil der Datensätze, die ich in Tabelle b über SELECT rausfinden kann löschen.
Und damit die zugehörigen Records aus der Tabelle a sollen gelöscht werden.

Problem:
Da die Datensätze in Tabelle b über aXb referenziert werden, muss ich natürlich
erst die Referenz aus aXb löschen (also die Fremdschlüssel).
Aber wie lautet die SQL-Anweisung, damit ich erst die Referenzen (meiner Auswahl an Daten aus Tabelle b) erst aus aXb
lösche, dann die zugehören Datensätze aus a und b löschen kann???
Ein „DELETE ON CASCADE“ ist in meinem speziellen Fall leider nicht möglich!

Herzlichen Dank,
Fabian

Hallo.

Wenn Du die Löschungen wirklich nicht kaskadieren kannst, würde ich das Problem folgendermaßen angehen :

Du hast drei Tabellen Tick, Trick und Track. In allen drei Tabellen (es sei denn, die Löschungen werden immer nur von Tick aus initiiert) ein Löschmarkierungsfeld vom Typ Boole vergeben.

Sei Tick die b-Tabelle, Trick die Zwischentabelle a-b, Track die a-Tabelle.

Gesetzt den Fall, ich habe Dich richtig verstanden, dann möchtest Du die Datensätze, die in Tick gelöscht werden sollen, gleichzeitig aus Trick und Track entfernen. Schrittweises Vorgehen muss aufgrund der RI und der Verknüpfungen so erfolgen, dass erst die Trick-Sätze, dann die Sätze aus den Ursprungstabellen entfernt werden.

Abfrage Donald SELECT Tick.Tickschlüssel FROM Tick WHERE Tick.Löschung=True;

Abfrage Daisy UPDATE Trick SET Trick.Löschung=True INNER JOIN ON (Trick.Tickschlüssel=Donald.Tickschlüssel);

Abfrage Gustav UPDATE Track SET Track.Löschung=True INNER JOIN ON (Track.Tickschlüssel=Donald.Tickschlüssel);

Abfrage Dagobert DELETE * FROM Trick WHERE Trick.Löschung=True;

Abfrage Dorette DELETE * FROM Track WHERE Track.Löschung=True;

Abfrage Daniel DELETE * FROM Tick WHERE Tick.Löschung=True;

Uff. Mangels SQL- Umgebung im Forum ungetestet; ich denke aber, dass diese Methode funktionieren sollte. Würde mich über eine Rückmeldung freuen …

Gruß kw

Hi!

Vorsicht ist geboten bei einer n:n - Beziehung, da ja Einträge von a in aXb auch Beziehungen zu b - Einträgen haben könnten,
die nicht in b gelöscht werden sollen. Dann fehlt nach der Löschung das a auf der a - Seite zu anderen b - Einträgen.

Ciao

Johannes

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

Hi Fabian,

ohne Dir zu nahe treten zu wollen: Die Anforderung klingt ein wenig obskur.

1- wähle ein b
2- suche alle a aus (a,b) zu diesem b
3- merke dir das Ergebnis für 4-
3- lösche die (a,b), die das b enthalten
4- lösche die in 2- gefundenen a aus (a)
5- lösche das b aus (b), von dem die Aktion ausging

Damit sterben auch die (a,b), die die gefundenen a enthalten.

Wozu soll das gut sein? Was hat der Kunde gewollt?

Gruß Ralf

Hi!

Ich vermute mal, es sollen nur alle die Sätze aus a gelöscht werden, die nach Löschung der Beziehungen aus aXb (zu den entsprechenden b-Sätzen) dann ganz ohne Beziehung in der aXb-Tabelle stehen, die quasi nach Löschung in b in der „Luft hängen“.

@Fabian: Oder ist etwas anderes gewollt?

Wenn ja, dann muss die Löschung in a auf solche Sätze eingeschränkt werden, die keinerlei Sätze in der Beziehungstabelle aXb mit nicht zu löschenden b-Sätzen haben. Unter oracle ist das mittels exists/not exists - Subselects einfach zu realisieren. Eigentlich ist da auch kein Löschflag in den Tabellen nötig. Nur zum Löschen sollte man ja nicht das logische/fachliche Datenmodell erweitern (müssen).

Ciao

Johannes

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

an Alle: Problem noch nicht gelöst!
Hallo Johannes und alle anderen :smile:
Vielen Dank für die Anregungen.

@Johannes:
Ganz richtig. es sollen nur alle die Sätze aus a,b gelöscht
werden, die nach Löschung der Beziehungen aus aXb (zu den
entsprechenden b-Sätzen) dann ganz ohne Beziehung in der
aXb-Tabelle stehen, wo vorher jedoch eine Beziehung existierte.
D.h. ich möchte aus der Tabelle a Datensätze selektieren, die ich
löschen möchte. Da diese jedoch über aXb referenziert werden muss
ich erst diese Referenz löschen. Das geht ja alles gut bis dahin,
denn ich sage:
delete from aXb where aXb.FK_a IN (select a_id where a.myAttr = ‚xy‘);
dann kann ich im 2. Schritt wie folgt vorgehen:
delete from a where where a.myAttr = ‚xy‘;
Problem ist nun, dass ich die Beziehung der Daten zu b verloren habe!

Dein Vorschlag haut nicht ganz hin, denn mit exist/Not exist
bekomme ich eventuell auch Datensätze, die zwar in
Tabellen a und b existieren, aber noch keine Beziehung in aXb haben.
Diese würde ich dann ebenfalls fälschlicherweise löschen :frowning:

@ Ralf:
Danke für den „Algorithmus“. Wie merke ich mir jedoch die Ergebnisse.
Muss ich da ein Stored Procedure schreiben und die Ergebnisse über
den „Cursor“ merken oder geht sowas auch mit SQL??

@ Alle:
Also mit log./phy. löschen wäre eine „saubere“ Alternative, doch leider kann ich nicht die Tabellen und die diese Attribute nachträglich erweitern…

Also das Problem ist noch offen!
Gruss,
Fabian

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

Hi!

Ist jetzt nicht wirklich performant aufgeschrieben (mehrfach verschachtelte Subselects), kann man über entsprechende JOINs tunen.

Aber versuch es mal ungefähr so:

  1. Zuerst alle die Datensätze in a löschen, die eine Beziehung in aXb zu einem zu löschenden b haben
    UND aber keine Beziehungen zu b-Sätzen haben, die nicht gelöscht werden sollen.
    delete a
    where a in ( select a from aXb aXb1
    where not exists ( select 1 from aXb aXb2 where aXb2.a = aXb1.a and aXb2.b not in (select b from b where …Deine Wahl…) )
    and aXb1.b in (select b from b where …Deine Wahl…)
    )

  2. Nun kann man ruhig alle Referenzen zu den b-Sätzen löschen.
    delete aXb where b in (select b from b where …Deine Wahl…)

  3. Und nun zuletzt dann die b-Sätze.
    delete from b where …Deine Wahl…

Ciao

Johannes

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

Hallo Johannes,
Danke für Deine Antwort.
Leider wird diese nicht funktionieren, denn wie bereits gesagt, kann
ich die Datensätze in Tabelle a erst dann löschen, wenn vorher
die referenzen in aXb Tabelle gelöscht sind
(wg. der referenziellen Integrität!).

D.h. ich bin gezwungen, erst die Datensätze in aXb zu löschen und
erst danach in a und b!!! Doch dies führt eben dazu, dass ich später
nicht mehr weiß, welche Daten ich in b zu löschen habe, da die referenzen in aXb bereits weg sind!

Gruss,
Fabian

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

Kannst Du diesen Constraint nicht für das Löschen deaktivieren oder (oracle-Bezeichnung) auf deffered setzen (dann wird erst beim commit der Constraint geprüft). Im Anschluss an die drei Löschstatements stimmt es ja wieder.

Ansonsten: Haben alle Einträge in a auch Einträge in aXb (logisch gesehen)?

Hallo Johannes,
Danke für Deine Antwort.
Leider wird diese nicht funktionieren, denn wie bereits
gesagt, kann
ich die Datensätze in Tabelle a erst dann löschen, wenn vorher
die referenzen in aXb Tabelle gelöscht sind
(wg. der referenziellen Integrität!).

D.h. ich bin gezwungen, erst die Datensätze in aXb zu löschen
und
erst danach in a und b!!! Doch dies führt eben dazu, dass ich
später
nicht mehr weiß, welche Daten ich in b zu löschen habe, da die
referenzen in aXb bereits weg sind!

Gruss,
Fabian

hum! Das wäre in der Tat eine Alternative! :smile:
Und zu Deiner Frage:
Nicht alle Einträge in a haben zwangsläufig Einträge in aXb.

Danke erstmal,
Viele Grüsse,
Fabian

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