PostgreSQL
 sql >> Datenbank >  >> RDS >> PostgreSQL

Postgresql löscht mehrere Zeilen aus mehreren Tabellen

Das Anordnen geeigneter kaskadierender Löschungen ist klug und normalerweise die richtige Lösung. Für bestimmte Sonderfälle gibt es eine andere Lösung, die relevant sein kann.

Wenn Sie mehrere Löschungen basierend auf einem gemeinsamen Datensatz durchführen müssen, können Sie verwenden Allgemeine Tabellenausdrücke (CTE) .

Es ist schwierig, ein einfaches Beispiel zu finden, da der Hauptanwendungsfall dafür durch kaskadierende Löschungen abgedeckt werden kann.

Für das Beispiel werden wir alle Elemente in Tabelle A löschen, deren Wert in der Wertemenge enthalten ist, die wir aus Tabelle B löschen. Normalerweise wären dies Schlüssel, aber wo sie es nicht sind, kann kaskadierendes Löschen nicht verwendet werden .

Um dies zu lösen, verwenden Sie CTEs

WITH Bdeletes AS (
    DELETE from B where IsSomethingToDelete = true returning ValueThatRelatesToA
)
delete from A where RelatedValue in (select ValueThatRelatesToA from Bdeletes)

Dieses Beispiel ist absichtlich einfach, weil es mir nicht darum geht, über Tastenzuordnungen usw. zu streiten, sondern zu zeigen, wie zwei oder mehr Löschungen von einem gemeinsam genutzten Datensatz ausgeführt werden können. Dies kann auch viel komplexer sein, einschließlich Aktualisierungsbefehlen usw.

Hier ist ein komplexeres Beispiel (aus der persönlichen Datenbank von Darth Vader). In diesem Fall haben wir eine Tabelle, die auf eine Adresstabelle verweist. Wir müssen Adressen aus der Adresstabelle löschen, wenn sie in seiner Liste der Planeten sind, die er zerstört hat. Wir möchten diese Informationen verwenden, um aus der Personentabelle zu löschen, aber nur, wenn sie auf dem Planeten waren (oder auf seiner Trophäen-Kill-Liste)

with AddressesToDelete as (
    select AddressId from Addresses a 
    join PlanetsDestroyed pd on pd.PlanetName = a.PlanetName
),
PeopleDeleted as (
    delete from People 
    where AddressId in (select * from AddressesToDelete)
    and OffPlanet = false 
    and TrophyKill = false
    returning Id
),
PeopleMissed as (
    update People 
    set AddressId=null, dead=(OffPlanet=false)
    where AddressId in (select * from AddressesToDelete)
    returning id
)
Delete from Addresses where AddressId in (select * from AddressesToDelete)

Jetzt ist seine Datenbank auf dem neuesten Stand. Keine Integritätsfehler aufgrund von Adresslöschung. Beachten Sie, dass wir zwar Daten von der Aktualisierung und der ersten Löschung zurückgeben, dies jedoch nicht bedeutet, dass wir sie verwenden müssen. Ich bin mir nicht sicher, ob Sie eine Löschung in einen CTE ohne zurückgegebene Daten einfügen können (My SQL kann auch bei der Verwendung der Rückkehr von einem Update falsch sein - ich konnte dies nicht testen, da Darth V. in a war schlechte Laune.