LU08e: N:M-Beziehungen mit Zwischentabelle abbilden

Ziel: Sie modellieren eine Many-to-Many-Beziehung (Posts ↔ Kategorien) korrekt mit einer Zwischentabelle post_category und füllen Daten-Zuordnungen.

Voraussetzung: Die Tabellen und Beispieldaten aus LU08c (users, posts, categories) sind vorhanden. (Die Verknüpfung users ↔ posts ist 1:N; posts ↔ categories ist N:M.)

Warum N:M auflösen?

In einer relationalen Tabelle kann ein Fremdschlüssel immer nur auf genau eine Zielzeile verweisen. Bei N:M gilt jedoch: ein Post → mehrere Kategorien und eine Kategorie → mehrere Posts. Das lässt sich mit einem FK-Feld nicht sauber abbilden:

Die folgenden Tabellen-Skizzen visualisieren diese Ansätze – alles sind schlechte Lösungen (siehe oben):

Lösung: die Zwischentabelle post_category. Wir trennen die Objekte (posts, categories) und speichern jede einzelne Zuordnung als eigene Zeile in post_category – genau ein Paar (post_id, category_id) pro Zeile. So bleibt jede Beziehung eindeutig modelliert, Primärschlüssel bleiben eindeutig, Fremdschlüssel sind prüfbar, und Abfragen bleiben klar und performant.

1:N vs N:M mit Zwischentabelle

users ↔ posts (1:N)

posts ↔ categories (N:M) – korrekt über Zwischentabelle post_category

1) Zwischentabelle anlegen (mit Fremdschlüsseln)

Eine Zeile = genau eine Zuordnung (post_id, category_id). CASCADE sorgt dafür, dass Zuordnungen automatisch gelöscht werden, wenn ein Post oder eine Kategorie gelöscht wird.

CREATE TABLE post_category (
post_id     INT NOT NULL,
category_id INT NOT NULL,
PRIMARY KEY (post_id, category_id),
FOREIGN KEY (post_id) REFERENCES posts (post_id) ON DELETE CASCADE ON UPDATE CASCADE,
FOREIGN KEY (category_id) REFERENCES categories (category_id) ON DELETE CASCADE ON UPDATE CASCADE
);

2) N:M-Zuordnungen einfügen

(IDs gemäss LU08c)

INSERT INTO post_category (post_id, category_id) VALUES
(1, 4),  -- Hasselt → Belgien
(1, 1),  -- Hasselt → Städtereise
 
(2, 5),  -- Utrecht → Niederlande
(2, 1),  -- Utrecht → Städtereise
 
(3, 6),  -- Lissabon → Portugal
(3, 1),  -- Lissabon → Städtereise
 
(4, 5),  -- Maastricht → Niederlande
(4, 1),  -- Maastricht → Städtereise
 
(5, 8),  -- Montenegro Roadtrip → Montenegro
(5, 2),  -- Montenegro Roadtrip → Abenteuer
(5, 3),  -- Montenegro Roadtrip → Roadtrip
 
(6, 9),  -- Oman → Oman
(6, 2),  -- Oman → Abenteuer
(6, 3),  -- Oman → Roadtrip
 
(7, 10), -- Chicago → USA
(7, 1);  -- Chicago → Städtereise 

3) Praxis: CASCADE

Beim Löschen eines Posts (oder einer Kategorie) werden die Zuordnungen in post_category automatisch entfernt.

-- Demo: Post #2 löschen
DELETE FROM posts WHERE post_id = 2;
 
-- Kontrolle: Mappings zu Post #2 sind weg
SELECT * FROM post_category WHERE post_id = 2; 

Erwartung: Die letzte Abfrage liefert keine Zeilen (CASCADE hat die Zuordnungen bereinigt).

4) Aufgaben

Zusammenfassung

Ausblick auf LU09: Wir formulieren dieselben Abfragen für mehrere Tabellen