Dies ist eine alte Version des Dokuments!
LU08c - Fremdschlüssel nachträglich hinzufügen und Referenzaktionen
Lernziele
- Ich kann mit ALTER TABLE eine Spalte und einen Fremdschlüssel zu einer bestehenden Tabelle hinzufügen.
- Ich kann die Referenzaktionen RESTRICT, CASCADE und SET NULL erklären.
- Ich kann für eine Beziehung begründen, welche Referenzaktion sinnvoll ist.
Ausgangslage
Führen Sie zuerst das Setup-Skript (travel_blog_setup.sql, in Moodle) aus. Damit hat Ihre Datenbank genau den Stand, von dem diese Seite ausgeht: Caro hat die user_id 1, Martin die 2, Shaolin die 3.
In der Praxis entsteht eine Datenbank selten in einem Zug. Oft existieren Tabellen schon mit Daten – und es kommt eine neue Spalte oder eine neue Verknüpfung dazu. Genau so ist es bei Ihren Cases aus LU05: Dort haben Sie die Fremdschlüssel-Spalten angelegt, aber noch nicht als Fremdschlüssel gesetzt. Das holen Sie mit ALTER TABLE nach.
ALTER TABLE
Spalte zu einer bestehenden Tabelle hinzufügen:
ALTER TABLE tabellenname ADD COLUMN neue_spalte DATENTYP;
Fremdschlüssel nachträglich setzen:
ALTER TABLE kind_tabelle ADD CONSTRAINT fk_name FOREIGN KEY (fremdschluessel) REFERENCES eltern_tabelle (primaerschluessel) ON DELETE referenzaktion;
fk_name ist ein frei wählbarer Name für die Regel, z.B. fk_posts_editor. So erkennen Sie in Fehlermeldungen sofort, welche Regel gegriffen hat.
Die drei Referenzaktionen
Mit ON DELETE legen Sie fest, was passiert, wenn eine Elternzeile gelöscht wird, auf die noch Kindzeilen verweisen:
| Referenzaktion | Was passiert mit den Kindzeilen? | Typisches Beispiel |
|---|---|---|
| RESTRICT | Nichts – das Löschen wird verhindert | Ein Autor mit Posts darf nicht gelöscht werden |
| CASCADE | Sie werden mitgelöscht | Wird ein Post gelöscht, verschwinden seine Kommentare |
| SET NULL | Sie bleiben, der Verweis wird leer (NULL) | Eine optionale Redaktorin wird gelöscht, der Post bleibt |
Wird keine Referenzaktion angegeben, gilt RESTRICT – das haben Sie in LU08b erlebt. (Genau genommen heisst der Standard in MySQL NO ACTION, verhält sich aber identisch.)
Neben ON DELETE gibt es auch ON UPDATE für das Ändern eines Primärschlüssels. Da Primärschlüssel in der Regel nie geändert werden, lassen wir das weg – es gilt dann ebenfalls RESTRICT.
Die Leitfrage für die Wahl: Ergibt die Kindzeile ohne ihre Elternzeile noch Sinn?
- Nein, sie wäre nutzlos → CASCADE
- Ja, der Verweis ist nur eine Zusatzinformation → SET NULL
- Das Löschen soll gar nicht erst möglich sein → RESTRICT
Beispiel 1: SET NULL
Jeder Post bekommt neu eine optionale Redaktorin (editor_id), die den Text gegenliest. Wird diese Person gelöscht, soll der Post erhalten bleiben – nur der Verweis fällt weg.
Spalte ergänzen und befüllen:
ALTER TABLE posts ADD COLUMN editor_id INT NULL; UPDATE posts SET editor_id = 2 WHERE post_id = 1; -- Hasselt: Martin liest gegen UPDATE posts SET editor_id = 1 WHERE post_id = 2; -- Utrecht: Caro liest gegen UPDATE posts SET editor_id = 3 WHERE post_id = 3; -- Lissabon: Shaolin liest gegen
Beachten Sie das NULL bei der Spalte: Ohne das wäre SET NULL gar nicht möglich, weil die Spalte keine leeren Werte erlauben würde.
Fremdschlüssel setzen:
ALTER TABLE posts ADD CONSTRAINT fk_posts_editor FOREIGN KEY (editor_id) REFERENCES users (user_id) ON DELETE SET NULL;
Testen:
DELETE FROM users WHERE username = 'shaolin'; SELECT post_id, title, editor_id FROM posts ORDER BY post_id;
Ergebnis: Shaolin ist gelöscht, der Lissabon-Post existiert weiterhin – seine editor_id ist jetzt NULL.
Warum durfte Shaolin hier gelöscht werden? Shaolin ist bei keinem Post als Autor eingetragen. Der Fremdschlüssel author_id mit RESTRICT greift also nicht. Versuchen Sie dasselbe mit Martin: Das scheitert weiterhin – nicht wegen editor_id, sondern wegen author_id.
Beispiel 2: CASCADE
Wir ergänzen eine Tabelle comments. Jeder Kommentar gehört zu genau einem Post. Ein Kommentar ohne Post ist nutzlos – wird der Post gelöscht, sollen seine Kommentare automatisch mit verschwinden.
Tabelle anlegen:
CREATE TABLE comments ( comment_id INT AUTO_INCREMENT PRIMARY KEY, post_id INT NOT NULL, author VARCHAR(100) NOT NULL, body TEXT NOT NULL, created_at DATETIME NOT NULL DEFAULT CURRENT_TIMESTAMP, FOREIGN KEY (post_id) REFERENCES posts (post_id) ON DELETE CASCADE );
Hier steht der Fremdschlüssel direkt im CREATE TABLE, wie in LU08b – Referenzaktionen funktionieren auf beiden Wegen.
Befüllen:
INSERT INTO comments (post_id, author, body) VALUES (2, 'Leser A', 'Toller Utrecht-Tipp!'), (2, 'Leserin B', 'Gute Café-Empfehlungen.'), (5, 'Reisefreund', 'Kotor war mein Highlight!');
Testen:
DELETE FROM posts WHERE post_id = 2; SELECT * FROM comments;
Ergebnis: Der Utrecht-Post ist gelöscht – und mit ihm beide Kommentare. Übrig bleibt nur der Kommentar zum Montenegro-Post.
CASCADE ist praktisch, aber mächtig: Ein einziger DELETE kann viele Zeilen in anderen Tabellen mitlöschen. Setzen Sie es nur dort ein, wo die Kindzeilen ohne ihre Elternzeile wirklich keinen Sinn mehr haben.
Zusammenfassung
| Referenzaktion | Wann einsetzen? |
|---|---|
| RESTRICT | Standard. Wenn das Löschen der Elternzeile verhindert werden soll. |
| CASCADE | Wenn die Kindzeilen ohne Elternzeile nutzlos sind (Kommentare, Zwischentabellen). |
| SET NULL | Wenn der Verweis optional ist und die Kindzeile bestehen bleiben soll. |
ON DELETE: NO ACTION, SET NULL, CASCADE, SET DEFAULT (9:22 min, deutsch). Quelle: Prof. Dr. Jens Dittrich / YouTube
Das Video zeigt zusätzlich SET DEFAULT – diese Option brauchen wir im Modul nicht.
