Unterschiede
Hier werden die Unterschiede zwischen zwei Versionen angezeigt.
| Beide Seiten der vorigen Revision Vorhergehende Überarbeitung Nächste Überarbeitung | Vorhergehende Überarbeitung | ||
| modul:m290_guko:learningunits:lu08:aufgaben:a_fk_in_lu05 [2025/10/19 23:38] – gkoch | modul:m290_guko:learningunits:lu08:aufgaben:a_fk_in_lu05 [2025/10/27 11:02] (aktuell) – gkoch | ||
|---|---|---|---|
| Zeile 1: | Zeile 1: | ||
| - | ====== | + | ====== |
| **Ziel der Übung:** | **Ziel der Übung:** | ||
| Zeile 12: | Zeile 12: | ||
| - | ==== 1) Ausgangsbasis | + | ==== 1) Ausgangsbasis ==== |
| * Öffnet eure **LU05-Datenbank** in WebStorm/ | * Öffnet eure **LU05-Datenbank** in WebStorm/ | ||
| * Prüft, dass **Primärschlüssel vorhanden** sind (wie in LU05), aber **keine** Fremdschlüssel. | * Prüft, dass **Primärschlüssel vorhanden** sind (wie in LU05), aber **keine** Fremdschlüssel. | ||
| * Falls ihr neu starten wollt: erstellt die Tabellen nochmals wie in LU05 (PK ja, FK noch nicht) und füllt ein paar **Beispieldaten** ein (mind. 3 Zeilen pro Tabelle). | * Falls ihr neu starten wollt: erstellt die Tabellen nochmals wie in LU05 (PK ja, FK noch nicht) und füllt ein paar **Beispieldaten** ein (mind. 3 Zeilen pro Tabelle). | ||
| + | * PDF mit Schema zu den einzelnen Cases: {{ : | ||
| Zeile 32: | Zeile 33: | ||
| **SQL-Muster (anpassen): | **SQL-Muster (anpassen): | ||
| + | <WRAP center box round 80%> | ||
| + | 1. Erstellen Sie eine neue Spalte für den Fremdschlüssel: | ||
| <code sql> | <code sql> | ||
| - | ALTER TABLE < | + | ALTER TABLE TABLE_NAME |
| - | ADD CONSTRAINT fk_<kind>_<eltern> | + | ADD COLUMN neue_spalte DATENTYP [AFTER bestehende_spalte]; |
| - | FOREIGN KEY (< | + | </code> |
| - | REFERENCES | + | 2. Setzen Sie die soeben erstellte Spalte als Fremdschlüssel (Foreign Key): |
| + | <code sql> | ||
| + | ALTER TABLE kind_tabelle | ||
| + | ADD FOREIGN KEY (neue_spalte) | ||
| + | REFERENCES eltern_tabelle(primaerschluessel_spalte) | ||
| ON DELETE RESTRICT | ON DELETE RESTRICT | ||
| ON UPDATE RESTRICT; | ON UPDATE RESTRICT; | ||
| </ | </ | ||
| + | </ | ||
| - | < | + | < |
| **Hinweise: | **Hinweise: | ||
| - | * Die **Eltern-Tabelle** (referenzierte Tabelle) muss **vorher existieren**. | + | |
| - | * Der **Datentyp** der FK-Spalte muss zum PK der Eltern passen (z. B. beide '' | + | * Der **Datentyp** der FK-Spalte muss zum PK der Eltern passen (z. B. beide '' |
| - | * '' | + | * '' |
| </ | </ | ||
| - | ==== 4) DML testen – zeigt RESTRICT in Aktion ==== | ||
| - | Führt die folgenden Mini-Tests in **eurem Case** durch. Erwartetes Verhalten jeweils in Klammern. | ||
| - | **A. INSERT (gültige vs. ungültige FK-Werte)** <code sql> | + | ==== 3) DML testen – RESTRICT erfahrbar machen ==== |
| - | -- gültig (Eltern existieren) | + | //DML = Data Manipulation Language |
| - | INSERT INTO < | + | |
| - | -- ungültig | + | **So gehen Sie vor (für euren gewählten Case):** |
| - | INSERT INTO < | + | |
| - | **B. DELETE Eltern (mit vorhandenen Kindern)** <code sql> | + | 1. **Daten anlegen** |
| - | -- sollte scheitern | + | 2. **Tests A–D** ausführen und das Verhalten beobachten |
| - | DELETE FROM < | + | |
| - | WHERE < | + | |
| - | **C. UPDATE FK in Kind (umhängen auf anderen Eltern-Datensatz)** <code sql> | + | > Hinweis: Falls eure Tabellennamen und Spaltennamen abweichen, dann müsst ihr das entsprechend ändern. Also entweder die hier erwähnten Codesnippets anpassen oder die Spaltennamen bei euch ändern. |
| - | -- erlaubt, solange der neue Eltern-Datensatz existiert | + | |
| - | UPDATE < | + | |
| - | SET < | + | |
| - | WHERE < | + | |
| - | **D. UPDATE PK in Eltern | + | === Case: Tierheim |
| - | -- in der Praxis selten und oft verhindert (RESTRICT). | + | |
| - | -- Erwartung: scheitert, wenn Kindzeilen darauf verweisen. | + | |
| - | UPDATE < | + | |
| - | SET < | + | |
| - | WHERE < | + | |
| - | < | + | **FK:** // |
| - | **Interpretation: | + | |
| - | Ihr erlebt, dass die Datenbank | + | **Daten** |
| - | Eltern | + | < |
| - | Kind-Datensätze dürfen umgehängt werden | + | INSERT INTO tierart (art_id, bezeichnung) VALUES (1,' |
| + | INSERT INTO tier (tier_id, name, geburtsdatum, | ||
| + | VALUES (101,' | ||
| + | </ | ||
| + | |||
| + | **Tests A–D** | ||
| + | <WRAP center box 80% round>< | ||
| + | -- A) INSERT: gültig vs. ungültig | ||
| + | INSERT INTO tier (tier_id, name, geburtsdatum, | ||
| + | VALUES (102,' | ||
| + | INSERT INTO tier (tier_id, name, geburtsdatum, | ||
| + | VALUES (103,' | ||
| + | |||
| + | -- B) DELETE Eltern | ||
| + | DELETE FROM tierart WHERE art_id = 1; -- sollte scheitern (RESTRICT), weil Tier 101 darauf zeigt | ||
| + | |||
| + | -- C) UPDATE FK im Kind (umhängen) | ||
| + | UPDATE tier SET art_id = 2 WHERE tier_id = 101; -- ok (Katze existiert jetzt) | ||
| + | |||
| + | -- D) UPDATE PK in Eltern | ||
| + | UPDATE tierart SET art_id = 5 WHERE art_id = 2; -- sollte scheitern, solange Tiere auf 2 verweisen </ | ||
| + | </ | ||
| + | |||
| + | |||
| + | === Case: Postzustellung (Postgebiet → viele Briefkästen) === | ||
| + | |||
| + | **FK:** // | ||
| + | |||
| + | **Daten** | ||
| + | <WRAP center box 80% round> | ||
| + | <code sql> | ||
| + | INSERT INTO postgebiet (gebiet_id, name, plz_bereich) VALUES (10,' | ||
| + | (20,' | ||
| + | INSERT INTO briefkasten (briefkasten_id, | ||
| + | VALUES (501,' | ||
| + | |||
| + | **Tests A–D** | ||
| + | <WRAP center box 80% round>< | ||
| + | -- A) INSERT | ||
| + | INSERT INTO briefkasten (briefkasten_id, | ||
| + | VALUES (502,' | ||
| + | INSERT INTO briefkasten (briefkasten_id, | ||
| + | VALUES (503,' | ||
| + | |||
| + | -- B) DELETE | ||
| + | DELETE FROM postgebiet WHERE gebiet_id = 10; -- scheitert (RESTRICT), weil BK 501 darauf zeigt | ||
| + | |||
| + | -- C) UPDATE FK im Kind | ||
| + | UPDATE briefkasten SET gebiet_id = 20 WHERE briefkasten_id = 501; -- ok (Gebiet 20 existiert) | ||
| + | |||
| + | -- D) UPDATE PK in Eltern | ||
| + | UPDATE postgebiet SET gebiet_id = 11 WHERE gebiet_id = 20; -- scheitert, solange Kinder | ||
| + | |||
| + | === Case: Online-Kleidershop (Kategorie → viele Kleidungsstücke) === | ||
| + | |||
| + | **FK:** // | ||
| + | |||
| + | **Daten** | ||
| + | <WRAP center box 80% round>< | ||
| + | INSERT INTO kategorie (kategorie_id, | ||
| + | INSERT INTO kleidungsstueck (artikel_id, | ||
| + | VALUES (9001,' | ||
| + | </ | ||
| + | |||
| + | **Tests A–D** | ||
| + | <WRAP center box 80% round>< | ||
| + | -- A) INSERT | ||
| + | INSERT INTO kleidungsstueck (artikel_id, | ||
| + | VALUES (9002,' | ||
| + | INSERT INTO kleidungsstueck (artikel_id, | ||
| + | VALUES (9003,' | ||
| + | |||
| + | -- B) DELETE Eltern | ||
| + | DELETE FROM kategorie WHERE kategorie_id = 1; -- scheitert (RESTRICT), Schuh 9001 existiert | ||
| + | |||
| + | -- C) UPDATE FK im Kind | ||
| + | UPDATE kleidungsstueck SET kategorie_id = 2 WHERE artikel_id = 9001; -- ok | ||
| + | |||
| + | -- D) UPDATE PK in Eltern | ||
| + | UPDATE kategorie SET kategorie_id = 5 WHERE kategorie_id = 2; -- scheitert bei referenzierten Zeilen </ | ||
| + | </ | ||
| + | |||
| + | === Case: Eishockeyverein (Team → viele Blöcke) === | ||
| + | |||
| + | **FK:** // | ||
| + | |||
| + | **Daten** | ||
| + | <WRAP center box 80% round>< | ||
| + | INSERT INTO team (team_id, name, altersklasse) VALUES (100,' | ||
| + | INSERT INTO block (block_id, bezeichnung, | ||
| + | </ | ||
| + | |||
| + | **Tests A–D** | ||
| + | <WRAP center box 80% round> | ||
| + | <code sql> | ||
| + | -- A) INSERT | ||
| + | INSERT INTO block (block_id, bezeichnung, | ||
| + | INSERT INTO block (block_id, bezeichnung, | ||
| + | |||
| + | -- B) DELETE Eltern | ||
| + | DELETE FROM team WHERE team_id = 100; -- scheitert (RESTRICT), Block 301 hängt dran | ||
| + | |||
| + | -- C) UPDATE FK im Kind | ||
| + | UPDATE block SET team_id = 200 WHERE block_id = 301; -- ok | ||
| + | |||
| + | -- D) UPDATE PK in Eltern | ||
| + | UPDATE team SET team_id = 250 WHERE team_id = 200; -- scheitert, wenn Blocks | ||
| + | </ | ||
| + | |||
| + | |||
| + | === Case: Öffentlicher Verkehr (Linie → viele Fahrten) === | ||
| + | |||
| + | **FK:** // | ||
| + | |||
| + | **Daten** | ||
| + | <WRAP center box 80% round> | ||
| + | <code sql> | ||
| + | INSERT INTO linie (linien_id, name, betreiber) VALUES (7,' | ||
| + | INSERT INTO fahrt (fahrt_id, datum, abfahrtszeit, | ||
| + | VALUES (7001,' | ||
| + | </ | ||
| + | |||
| + | **Tests A–D** | ||
| + | <WRAP center box 80% round> | ||
| + | <code sql> | ||
| + | -- A) INSERT | ||
| + | INSERT INTO fahrt (fahrt_id, datum, abfahrtszeit, | ||
| + | VALUES (7002,' | ||
| + | INSERT INTO fahrt (fahrt_id, datum, abfahrtszeit, | ||
| + | VALUES (7003,' | ||
| + | |||
| + | -- B) DELETE | ||
| + | DELETE FROM linie WHERE linien_id = 7; -- scheitert (RESTRICT) | ||
| + | |||
| + | -- C) UPDATE FK im Kind | ||
| + | UPDATE fahrt SET linien_id = 9 WHERE fahrt_id = 7001; -- ok | ||
| + | |||
| + | -- D) UPDATE PK in Eltern | ||
| + | UPDATE linie SET linien_id = 10 WHERE linien_id = 9; -- scheitert bei referenzierten Zeilen | ||
| + | </ | ||
| + | </ | ||
| + | |||
| + | |||
| + | === Case: Schweizer Regionen (Kanton → viele Gemeinden) === | ||
| + | |||
| + | **FK:** //gemeinde.kanton_id// → // | ||
| + | |||
| + | **Daten** | ||
| + | <WRAP center box 80% round> | ||
| + | <code sql> | ||
| + | INSERT INTO kanton (kanton_id, name, einwohnerzahl, | ||
| + | (2,' | ||
| + | INSERT INTO gemeinde (gemeinde_id, | ||
| + | VALUES (10001,' | ||
| + | </ | ||
| + | </ | ||
| + | |||
| + | **Tests A–D** | ||
| + | <WRAP center box 80% round>< | ||
| + | -- A) INSERT | ||
| + | INSERT INTO gemeinde (gemeinde_id, | ||
| + | VALUES (10002,' | ||
| + | INSERT INTO gemeinde (gemeinde_id, | ||
| + | VALUES (10003,' | ||
| + | |||
| + | -- B) DELETE Eltern | ||
| + | DELETE FROM kanton WHERE kanton_id = 1; -- scheitert (RESTRICT), Zürich hängt dran | ||
| + | |||
| + | -- C) UPDATE FK im Kind | ||
| + | UPDATE gemeinde SET kanton_id = 2 WHERE gemeinde_id = 10001; | ||
| + | |||
| + | -- D) UPDATE PK in Eltern | ||
| + | UPDATE kanton SET kanton_id = 3 WHERE kanton_id = 2; -- scheitert bei referenzierten Zeilen | ||
| + | </ | ||
| </ | </ | ||
| - | ==== 5) (Optional) SET NULL oder CASCADE bewusst einsetzen ==== | + | ==== 4) (Optional) SET NULL oder CASCADE bewusst einsetzen ==== |
| Falls in **eurem Modell** eine Beziehung **optional** ist (FK darf NULL sein), könnt ihr '' | Falls in **eurem Modell** eine Beziehung **optional** ist (FK darf NULL sein), könnt ihr '' | ||
| Zeile 96: | Zeile 262: | ||
| </ | </ | ||
| - | *Einsatzbeispiel: | + | //Einsatzbeispiel: |
| **CASCADE** verwenden wir bevorzugt bei **Zwischentabellen** (N:M). | **CASCADE** verwenden wir bevorzugt bei **Zwischentabellen** (N:M). | ||
| - | Falls euer Case eine N: | + | Falls euer Case eine N: |
| Für reine 1: | Für reine 1: | ||
| - | ==== 6) Abgabe (pro Gruppe) ==== | + | ==== 5) Abgabe (pro Gruppe) ==== |
| - | **Kurz-Beschrieb (Word-Dokument/PDF, max. 1 Seite)** mit: | + | **Kurz-Beschrieb (Word-Dokument |
| * ERD (Crow’s Foot) mit PK/FK markiert. | * ERD (Crow’s Foot) mit PK/FK markiert. | ||
| * Liste eurer **ALTER TABLE**-Befehle (FK-Namen, ON DELETE/ | * Liste eurer **ALTER TABLE**-Befehle (FK-Namen, ON DELETE/ | ||