Also, wir wissen schon, was Fremdschlüssel (FOREIGN KEY) sind, wie sie funktionieren und haben sogar schon geübt, Tabellen damit zu erstellen. Aber was, wenn es Zeit ist, Daten zu löschen oder verknüpfte Einträge zu ändern? Genau das schauen wir uns jetzt an: Wie funktionieren Löschen und Ändern von Daten zusammen mit Fremdschlüsseln und welche Tricks gibt es dabei?
Stell dir vor, die Datenbank ist wie ein kompliziertes Kartenhaus. Wenn du eine Karte rausziehst, kann das ganze Ding zusammenfallen. Genau hier kommen Fremdschlüssel ins Spiel, die verhindern, dass unsere Datenbank beim Löschen von verknüpften Daten "einstürzt". Lass uns anschauen, wie das läuft.
Was passiert, wenn man versucht, Daten zu löschen?
Wenn es in einer Tabelle einen Fremdschlüssel gibt, prüft das DBMS, ob der Eintrag mit anderen Tabellen verknüpft ist. Falls ja, kann das Löschen zu einem Integritätsfehler führen. Damit es keine bösen Überraschungen gibt, kann man vorher Aktionen für den Fremdschlüssel festlegen. Diese Aktionen werden mit den Optionen ON DELETE eingestellt.
Verhalten mit ON DELETE einstellen
Du kannst beim Erstellen des Fremdschlüssels eine der folgenden Regeln festlegen:
ON DELETE CASCADE: Wenn ein Eintrag in der übergeordneten Tabelle gelöscht wird, werden automatisch alle verknüpften Einträge in der Kind-Tabelle gelöscht.ON DELETE SET NULL: Statt die verknüpften Einträge zu löschen, wird deren Fremdschlüssel aufNULLgesetzt.ON DELETE SET DEFAULT: Der Fremdschlüssel bekommt den Default-Wert.ON DELETE RESTRICT(Standardverhalten): Löschen ist nicht möglich, wenn es verknüpfte Einträge gibt – es gibt einen Fehler.ON DELETE NO ACTION: Fast wieRESTRICT, aber die Integritätsprüfung wird erst am Ende der Transaktion gemacht.
Beispiel: Kaskadierendes Löschen ON DELETE CASCADE
-- Kundentabelle
CREATE TABLE customers (
customer_id SERIAL PRIMARY KEY,
name TEXT NOT NULL
);
-- Bestellungen-Tabelle
CREATE TABLE orders (
order_id SERIAL PRIMARY KEY,
customer_id INT REFERENCES customers(customer_id) ON DELETE CASCADE,
order_date DATE NOT NULL
);
-- Daten einfügen
INSERT INTO customers (name) VALUES ('Ivan Ivanov');
INSERT INTO orders (customer_id, order_date) VALUES (1, '2023-10-01');
-- Kunde löschen
DELETE FROM customers WHERE customer_id = 1;
-- Checken, was mit der Tabelle orders passiert ist
SELECT * FROM orders; -- Keine Einträge mehr, sie wurden kaskadiert gelöscht!
Wenn wir einen Eintrag aus der Tabelle customers löschen, löscht PostgreSQL automatisch alle Bestellungen dieses Kunden aus der Tabelle orders.
Beispiel: Fremdschlüssel auf NULL setzen ON DELETE SET NULL
-- Bestellungen-Tabelle mit neuem Verhalten
CREATE TABLE orders_with_null (
order_id SERIAL PRIMARY KEY,
customer_id INT REFERENCES customers(customer_id) ON DELETE SET NULL,
order_date DATE NOT NULL
);
-- Daten einfügen
INSERT INTO orders_with_null (customer_id, order_date) VALUES (1, '2023-10-01');
-- Kunde löschen
DELETE FROM customers WHERE customer_id = 1;
-- Tabelle orders_with_null checken
SELECT * FROM orders_with_null;
Ergebnis:
| order_id | customer_id | order_date |
|---|---|---|
| 1 | NULL | 2023-10-01 |
Mit ON DELETE SET NULL können wir die Bestellungen behalten, aber sie sind jetzt nicht mehr mit einem existierenden Kunden verknüpft.
Daten ändern mit Fremdschlüsseln
Neben dem Löschen können auch Änderungen in der übergeordneten Tabelle Auswirkungen auf verknüpfte Einträge haben. Was passiert zum Beispiel, wenn ein Kunde seine customer_id ändert? Hier kommt die Option ON UPDATE ins Spiel.
Verhalten mit ON UPDATE einstellen
Änderungen in der übergeordneten Tabelle kannst du mit folgenden Strategien behandeln:
ON UPDATE CASCADE: Wenn sich der Wert des Fremdschlüssels in der übergeordneten Tabelle ändert, wird er automatisch in allen verknüpften Einträgen aktualisiert.ON UPDATE SET NULL: Der Fremdschlüssel in den Kind-Tabellen wird aufNULLgesetzt.ON UPDATE SET DEFAULT: Es wird der Default-Wert gesetzt.ON UPDATE RESTRICT: Änderung des Fremdschlüssels ist verboten, wenn es verknüpfte Einträge gibt.ON UPDATE NO ACTION: Die Prüfung wird bis zum Ende der Transaktion aufgeschoben.
Beispiel: Kaskadierendes Update ON UPDATE CASCADE
CREATE TABLE customers_with_cascade (
customer_id SERIAL PRIMARY KEY,
name TEXT NOT NULL
);
CREATE TABLE orders_with_cascade (
order_id SERIAL PRIMARY KEY,
customer_id INT REFERENCES customers_with_cascade(customer_id) ON UPDATE CASCADE,
order_date DATE NOT NULL
);
-- Daten einfügen
INSERT INTO customers_with_cascade (name) VALUES ('Ivan Ivanov');
INSERT INTO orders_with_cascade (customer_id, order_date) VALUES (1, '2023-10-01');
-- customer_id ändern
UPDATE customers_with_cascade SET customer_id = 100 WHERE customer_id = 1;
-- Tabelle orders_with_cascade checken
SELECT * FROM orders_with_cascade;
Ergebnis:
| order_id | customer_id | order_date |
|---|---|---|
| 1 | 100 | 2023-10-01 |
Wenn sich customer_id ändert, aktualisiert PostgreSQL den Wert automatisch in der Tabelle orders_with_cascade.
Praxis: Tabelle enrollments
Erinnern wir uns an unser Beispiel mit den Studenten students und den Kursen courses. Wir arbeiten jetzt mit der Tabelle für Kursanmeldungen enrollments und konfigurieren das Löschen von Daten.
-- Studententabelle
CREATE TABLE students (
student_id SERIAL PRIMARY KEY,
name TEXT NOT NULL
);
-- Kurstabelle
CREATE TABLE courses (
course_id SERIAL PRIMARY KEY,
title TEXT NOT NULL
);
-- Zwischentabelle für Anmeldungen
CREATE TABLE enrollments (
student_id INT REFERENCES students(student_id) ON DELETE CASCADE,
course_id INT REFERENCES courses(course_id) ON DELETE CASCADE,
PRIMARY KEY (student_id, course_id)
);
-- Daten einfügen
INSERT INTO students (name) VALUES ('Aleksej Petrov');
INSERT INTO courses (title) VALUES ('Mathematik');
INSERT INTO enrollments (student_id, course_id) VALUES (1, 1);
-- Student löschen
DELETE FROM students WHERE student_id = 1;
-- Tabelle enrollments checken
SELECT * FROM enrollments; -- Leer! Der Eintrag wurde automatisch gelöscht.
Typische Fehler und wie man sie vermeidet
Ein häufiger Fehler ist der Versuch, einen Eintrag aus der übergeordneten Tabelle zu löschen, ohne das Verhalten der Fremdschlüssel richtig zu konfigurieren. Wenn du zum Beispiel nichts für ON DELETE angibst, wird standardmäßig RESTRICT verwendet – das führt zu einem Fehler.
Außerdem solltest du daran denken, dass zu häufiges Verwenden von Kaskaden-Operationen (CASCADE) zu unerwarteten Folgen führen kann. Du könntest zum Beispiel mehr Daten löschen als geplant.
Damit dir sowas nicht passiert, halte dich an diese Tipps:
- Denk immer gut über das Verhalten von
ON DELETEundON UPDATEnach – je nachdem, wie deine App funktioniert. - Für besonders wichtige Aktionen: Mach vorher Prüf-Abfragen, bevor du etwas änderst oder löschst.
- Nutze Transaktionen, damit du Änderungen im Fehlerfall zurückrollen kannst.
GO TO FULL VERSION