Stell dir vor, du hast eine Datenbank gebaut, in der es eine Kundentabelle (customers) und dazugehörige Bestellungen (orders) gibt. Aber irgendwann kommt die Frage auf: Was passiert, wenn ein Kunde aus der Tabelle customers gelöscht wird? Sollen dann auch die Bestellungen dieses Kunden gelöscht werden oder bleiben sie als "Waisen" zurück und verweisen auf einen nicht mehr existierenden Kunden? Und was, wenn du die ID eines Kunden ändern willst? Genau hier kommen Kaskadenoperationen (CASCADE) und Einschränkungen (RESTRICT) ins Spiel, um das Verhalten der Datenbank zu steuern.
ON DELETE CASCADE ist ein Mechanismus, der automatisch alle verbundenen Datensätze löscht, wenn ein Eintrag aus der übergeordneten Tabelle entfernt wird. Mit anderen Worten: Wenn du einen Kunden löschst, werden auch alle seine Bestellungen gelöscht.
Das funktioniert so: Wenn du ON DELETE CASCADE beim Definieren eines Fremdschlüssels hinzufügst, "weiß" die Datenbank, dass der verbundene Datensatz automatisch gelöscht werden soll.
Beispiel
Nehmen wir an, wir haben zwei Tabellen: customers und orders. Kunden (customers) können mehrere Bestellungen (orders) machen, das entspricht einer ONE-TO-MANY-Beziehung. Wir wollen, dass beim Löschen eines Kunden auch alle seine Bestellungen gelöscht werden.
-- Wir erstellen die Kundentabelle
CREATE TABLE customers (
customer_id SERIAL PRIMARY KEY,
name TEXT NOT NULL
);
-- Wir erstellen die Bestelltabelle mit einem Fremdschlüssel, der auf die Kundentabelle verweist
CREATE TABLE orders (
order_id SERIAL PRIMARY KEY,
customer_id INT REFERENCES customers(customer_id) ON DELETE CASCADE,
order_date DATE NOT NULL
);
Daten in die Tabellen einfügen
-- Wir fügen Daten in die Kundentabelle ein
INSERT INTO customers (name) VALUES ('Ivan'), ('Anna');
-- Wir fügen Daten in die Bestelltabelle ein
INSERT INTO orders (customer_id, order_date) VALUES
(1, '2023-10-01'),
(1, '2023-10-02'),
(2, '2023-10-03');
Tabelle orders:
| order_id | customer_id | order_date |
|---|---|---|
| 1 | 1 | 2023-10-01 |
| 2 | 1 | 2023-10-02 |
| 3 | 2 | 2023-10-03 |
Kunde löschen und schauen, was passiert
-- Wir löschen den Kunden mit ID 1
DELETE FROM customers WHERE customer_id = 1;
-- Wir prüfen, was in der Bestelltabelle übrig bleibt
SELECT * FROM orders;
| order_id | customer_id | order_date |
|---|---|---|
| 3 | 2 | 2023-10-03 |
Wie du siehst, wurden die Bestellungen, die mit dem gelöschten Kunden verbunden waren, ebenfalls gelöscht.
Änderungen einschränken: ON UPDATE RESTRICT
ON UPDATE RESTRICT sorgt dafür, dass du einen Wert in der übergeordneten Tabelle nicht ändern kannst, wenn ein Eintrag in der untergeordneten Tabelle darauf verweist. Das ist so eine Art "Schutzbarriere", die verhindert, dass Änderungen gemacht werden, die die Datenintegrität zerstören könnten.
Wie funktioniert das? Wenn du ON UPDATE RESTRICT hinzufügst, lässt die Datenbank keine Änderung des Schlüssels in der übergeordneten Tabelle zu, solange darauf in der untergeordneten Tabelle verwiesen wird.
Beispiel
Wir nehmen wieder die gleichen Tabellen customers und orders, aber diesmal fügen wir beim Fremdschlüssel eine Einschränkung für Änderungen hinzu.
-- Wir erstellen die Bestelltabelle neu mit Einschränkung für Updates
DROP TABLE orders;
CREATE TABLE orders (
order_id SERIAL PRIMARY KEY,
customer_id INT REFERENCES customers(customer_id) ON UPDATE RESTRICT,
order_date DATE NOT NULL
);
Versuchen wir, die Kunden-ID zu ändern
-- Versuch, die Kunden-ID von 2 auf 5 zu ändern
UPDATE customers
SET customer_id = 5
WHERE customer_id = 2;
Ergebnis:
ERROR: update or delete on table "customers" violates foreign key constraint
DETAIL: Key (customer_id)=(2) is still referenced from table "orders".
Wie du siehst, hat die Datenbank einen Fehler geworfen, weil das Ändern des Schlüssels die Verbindung zwischen den Tabellen zerstören würde.
Mehr Details zu UPDATE und wie das alles genau funktioniert, gibt's im nächsten Level :P
Kombination von ON DELETE CASCADE und ON UPDATE RESTRICT
Klar, Kaskadenoperationen (CASCADE) und Einschränkungen (RESTRICT) kann man auch kombinieren. Zum Beispiel kannst du das automatische Löschen von verbundenen Daten beim Löschen eines übergeordneten Eintrags (ON DELETE CASCADE) aktivieren, aber gleichzeitig das Ändern der ID verbieten (ON UPDATE RESTRICT), um unerwünschte Folgen zu vermeiden.
Beispiel
Wir erstellen die Bestelltabelle nochmal, diesmal mit beiden Mechanismen:
DROP TABLE orders;
CREATE TABLE orders (
order_id SERIAL PRIMARY KEY,
customer_id INT REFERENCES customers(customer_id)
ON DELETE CASCADE
ON UPDATE RESTRICT,
order_date DATE NOT NULL
);
Jetzt gilt:
- Wenn du einen Kunden löschst, werden alle seine Bestellungen gelöscht.
- Wenn du versuchst, die Kunden-ID zu ändern, bekommst du einen Fehler.
Warum ist das in echten Projekten wichtig?
Die Verwendung von CASCADE und RESTRICT ist super wichtig für große Systeme mit vielen verbundenen Tabellen. Zum Beispiel:
In einem Online-Shop kann ein Kunde Bestellungen haben. Wenn der Kunde sein Profil löscht, willst du keine Bestellungen in der Datenbank lassen, die auf nichts mehr verweisen. Hier hilft ON DELETE CASCADE.
Gleichzeitig willst du vielleicht verhindern, dass jemand aus Versehen einen eindeutigen Schlüssel ändert und damit die Verbindungen zwischen den Tabellen zerstört. Dafür ist ON UPDATE RESTRICT praktisch.
GO TO FULL VERSION