Unterschiede
Hier werden die Unterschiede zwischen zwei Versionen angezeigt.
| Nächste Überarbeitung | Vorhergehende Überarbeitung | ||
| modul:m290_guko:learningunits:lu08:aufgaben:a_fk_in_lu05 [2025/10/19 23:19] – angelegt 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:** | ||
| - | Ihr greift euren **LU05-Case** wieder auf (z. B. *Tierheim*, *Postzustellung*, *Online-Kleidershop*, *Eishockeyverein*, *ÖV*, *Schweizer Regionen*). | + | Ihr greift euren **LU05-Case** wieder auf (z. B. //Tierheim//, //Postzustellung//, //Online-Kleidershop//, //Eishockeyverein//, //ÖV//, //Schweizer Regionen//). |
| Damals habt ihr Tabellen **ohne** Fremdschlüssel erstellt und Daten via WebStorm-Interface eingefügt. | Damals habt ihr Tabellen **ohne** Fremdschlüssel erstellt und Daten via WebStorm-Interface eingefügt. | ||
| Jetzt | Jetzt | ||
| - | + | - ergänzt ihr **Fremdschlüssel mit ALTER TABLE**, | |
| - | 1. ergänzt ihr **Fremdschlüssel mit ALTER TABLE**, | + | |
| - | 2. testet die **Referenzaktionen** (Standard: RESTRICT), | + | |
| - | 3. übt **DML** (INSERT, UPDATE, DELETE) aus LU07. | + | |
| Arbeitsform: | Arbeitsform: | ||
| - | --- | ||
| - | ==== 1) Ausgangsbasis | + | ==== 1) Ausgangsbasis ==== |
| - | * Ö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–5 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: {{ :modul: | |
| - | <WRAP tip> | + | |
| - | **Tipp:** Arbeitet in einem **neuen Schema** (z. B. '' | + | |
| - | </ | + | |
| - | --- | ||
| ==== 2) Fremdschlüssel mit ALTER TABLE hinzufügen ==== | ==== 2) Fremdschlüssel mit ALTER TABLE hinzufügen ==== | ||
| Analysiert euer ERD (Crow’s Foot aus LU05). Legt für **jede 1: | Analysiert euer ERD (Crow’s Foot aus LU05). Legt für **jede 1: | ||
| - | Beispiele | + | Beispiele: |
| - | * **Tierheim: | + | |
| - | '' | + | * **Postzustellung:** // |
| - | '' | + | * **Online-Kleidershop: |
| + | * **Eishockeyverein: | ||
| + | * **ÖV:** // | ||
| + | * **Schweizer Regionen:** // | ||
| - | * **Postzustellung:** | + | **SQL-Muster (anpassen):** |
| - | '' | + | <WRAP center box round 80%> |
| - | '' | + | 1. Erstellen Sie eine neue Spalte für den Fremdschlüssel: |
| + | <code sql> | ||
| + | ALTER TABLE TABLE_NAME | ||
| + | ADD COLUMN neue_spalte DATENTYP [AFTER bestehende_spalte]; | ||
| + | </ | ||
| + | 2. Setzen Sie die soeben erstellte Spalte als Fremdschlüssel | ||
| + | <code sql> | ||
| + | ALTER TABLE kind_tabelle | ||
| + | ADD FOREIGN KEY (neue_spalte) | ||
| + | REFERENCES eltern_tabelle(primaerschluessel_spalte) | ||
| + | ON DELETE RESTRICT | ||
| + | ON UPDATE RESTRICT; | ||
| + | </ | ||
| + | </ | ||
| - | * **Online-Kleidershop: | + | <WRAP center box round 80%> |
| - | | + | **Hinweise:** |
| - | '' | + | * Die **Eltern-Tabelle** (referenzierte Tabelle) muss **vorher existieren**. |
| + | | ||
| + | | ||
| + | </ | ||
| - | * **Eishockeyverein: | ||
| - | '' | ||
| - | '' | ||
| - | '' | ||
| - | * **ÖV (vereinfacht): | ||
| - | '' | ||
| - | '' | ||
| - | * **Schweizer Regionen: | + | ==== 3) DML testen – RESTRICT erfahrbar machen ==== |
| - | '' | + | //DML = Data Manipulation Language -> Daten einfügen, ändern, löschen// |
| - | '' | + | |
| - | **SQL-Muster | + | **So gehen Sie vor (für euren gewählten Case):** |
| - | ALTER TABLE < | + | |
| - | ADD CONSTRAINT fk_< | + | |
| - | FOREIGN KEY (< | + | |
| - | REFERENCES < | + | |
| - | ON DELETE RESTRICT | + | |
| - | ON UPDATE RESTRICT; </ | + | |
| - | <WRAP info> | + | 1. **Daten anlegen** |
| - | **Hinweise:** | + | 2. **Tests A–D** ausführen und das Verhalten beobachten |
| - | * Die **Eltern-Tabelle** (referenzierte Tabelle) muss **vorher existieren**. | + | |
| - | * Der **Datentyp** der FK-Spalte muss zum PK der Eltern passen | + | > 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. |
| - | * '' | + | |
| + | === Case: Tierheim (Tierart → viele Tiere) == | ||
| + | |||
| + | **FK:** //tier.art_id// → // | ||
| + | |||
| + | **Daten** | ||
| + | <WRAP center box 80% round>< | ||
| + | INSERT INTO tierart | ||
| + | INSERT INTO tier (tier_id, name, geburtsdatum, | ||
| + | VALUES (101,'Luna','2022-05-10',' | ||
| </ | </ | ||
| - | --- | + | **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 mit Kind | ||
| + | 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) === | ||
| - | ==== 3) Konsistenz prüfen (Orphans suchen) ==== | + | **FK:** // |
| - | Bevor ihr FKs setzt, | + | |
| + | **Daten** | ||
| + | <WRAP center box 80% round> | ||
| <code sql> | <code sql> | ||
| - | -- Beispiel: Kinder ohne Eltern finden | + | INSERT INTO postgebiet (gebiet_id, name, plz_bereich) VALUES (10,' |
| - | SELECT k.* | + | (20,' |
| - | FROM < | + | INSERT INTO briefkasten (briefkasten_id, |
| - | LEFT JOIN < | + | VALUES (501,' |
| - | | + | |
| - | WHERE e.< | + | |
| - | </code> | + | |
| - | *Falls es Treffer gibt:* Korrigiert die Werte (UPDATE) oder löscht fehlerhafte Zeilen | + | **Tests A–D** |
| + | <WRAP center box 80% round>< | ||
| + | -- A) INSERT | ||
| + | INSERT INTO briefkasten | ||
| + | VALUES | ||
| + | INSERT INTO briefkasten (briefkasten_id, standort, leerungszeit, | ||
| + | VALUES (503,' | ||
| - | --- | + | -- B) DELETE Eltern |
| + | DELETE FROM postgebiet WHERE gebiet_id = 10; -- scheitert (RESTRICT), weil BK 501 darauf zeigt | ||
| - | ==== 4) DML testen – zeigt RESTRICT in Aktion | + | -- C) UPDATE FK im Kind |
| - | Führt die folgenden Mini-Tests in **eurem Case** durch. Erwartetes Verhalten jeweils in Klammern. | + | UPDATE briefkasten SET gebiet_id |
| - | **A. INSERT (gültige vs. ungültige FK-Werte)** <code sql> | + | -- D) UPDATE PK in Eltern |
| - | -- gültig (Eltern existieren) | + | UPDATE postgebiet SET gebiet_id = 11 WHERE gebiet_id = 20; -- scheitert, solange Kinder auf 20 zeigen |
| - | INSERT INTO < | + | |
| - | -- ungültig | + | === Case: Online-Kleidershop |
| - | INSERT INTO < | + | |
| - | **B. DELETE Eltern (mit vorhandenen Kindern)** <code sql> | + | **FK:** // |
| - | -- sollte scheitern (RESTRICT) | + | |
| - | DELETE FROM < | + | |
| - | WHERE < | + | |
| - | **C. UPDATE FK in Kind (umhängen auf anderen Eltern-Datensatz)** <code sql> | + | **Daten** |
| - | -- erlaubt, solange der neue Eltern-Datensatz existiert | + | <WRAP center box 80% round><code sql> |
| - | UPDATE < | + | INSERT INTO kategorie (kategorie_id, name) VALUES (1,' |
| - | SET <fk_spalte> | + | INSERT INTO kleidungsstueck (artikel_id, |
| - | WHERE < | + | VALUES (9001,' |
| + | </WRAP> | ||
| - | **D. UPDATE PK in Eltern (Primärschlüsselwert ändern)** <code sql> | + | **Tests A–D** |
| - | -- in der Praxis selten und oft verhindert | + | <WRAP center box 80% round><code sql> |
| - | -- Erwartung: scheitert, wenn Kindzeilen darauf verweisen. | + | -- A) INSERT |
| - | UPDATE < | + | INSERT INTO kleidungsstueck |
| - | SET < | + | VALUES (9002,' |
| - | WHERE < | + | INSERT INTO kleidungsstueck (artikel_id, name, preis, groesse, zielgruppe, kategorie_id) |
| + | VALUES (9003,' | ||
| - | <WRAP tip> | + | -- B) DELETE Eltern |
| - | **Interpretation: | + | DELETE FROM kategorie WHERE kategorie_id = 1; -- scheitert (RESTRICT), Schuh 9001 existiert |
| - | Ihr erlebt, dass die Datenbank mit **RESTRICT** die **Datenintegrität** schützt: | + | |
| - | Eltern lassen sich nicht löschen/ | + | -- C) UPDATE FK im Kind |
| - | Kind-Datensätze dürfen umgehängt werden – aber nur auf **existierende** | + | 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) === |
| - | ==== 5) (Optional) SET NULL oder CASCADE bewusst einsetzen ==== | + | **FK:** // |
| - | Falls in **eurem Modell** eine Beziehung **optional** ist (FK darf NULL sein), könnt ihr '' | + | |
| + | **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> | <code sql> | ||
| - | ALTER TABLE < | + | -- A) INSERT |
| - | | + | INSERT INTO block (block_id, bezeichnung, |
| - | | + | INSERT INTO block (block_id, bezeichnung, |
| - | REFERENCES < | + | |
| - | ON DELETE SET NULL | + | |
| - | ON UPDATE RESTRICT; | + | |
| - | </ | + | |
| - | *Einsatzbeispiel: | + | -- B) DELETE Eltern |
| + | DELETE FROM team WHERE team_id = 100; -- scheitert (RESTRICT), Block 301 hängt dran | ||
| - | **CASCADE** verwenden wir bevorzugt bei **Zwischentabellen** (N:M). | + | -- C) UPDATE FK im Kind |
| - | Falls euer Case eine N:M-Erweiterung hat (z. B. im Kleidershop: | + | UPDATE block SET team_id = 200 WHERE block_id = 301; -- ok |
| - | Für reine 1:N-Beziehungen bleibt **RESTRICT** meist die beste Wahl. | + | |
| - | --- | + | -- D) UPDATE PK in Eltern |
| + | UPDATE team SET team_id = 250 WHERE team_id = 200; -- scheitert, wenn Blocks auf 200 zeigen </ | ||
| + | </ | ||
| - | ==== 6) Abgabe (pro Gruppe) ==== | ||
| - | 1. **Kurz-Doku | + | === Case: Öffentlicher Verkehr |
| - | * ERD (Crow’s Foot) mit PK/FK markiert. | + | **FK:** //fahrt.linien_id// → //linie.linien_id// |
| - | * Liste eurer **ALTER TABLE**-Befehle (FK-Namen, ON DELETE/ | + | |
| - | * 3–5 **DML-Beispiele** (INSERT/UPDATE/DELETE) inkl. kurzer Interpretation des Verhaltens (z. B. Fehlermeldung bei RESTRICT). | + | |
| - | 2. **SQL-Datei** mit allen ausgeführten **ALTER/INSERT/UPDATE/DELETE** (in sinnvoller Reihenfolge). | + | |
| - | 3. **Kurz-Demo** (2–3 Minuten): Ein FK-Fehler **zeigen** und erklären, warum er sinnvoll ist. | + | |
| - | < | + | **Daten** |
| - | **Bewertung | + | < |
| - | Vollständigkeit FK (40 %), saubere DML-Tests & Interpretation | + | <code sql> |
| + | INSERT INTO linie (linien_id, name, betreiber) VALUES | ||
| + | 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,' | ||
| - | ==== Anhang: Vorlagen je Case (FK-Skizzen) ==== | + | -- B) DELETE Eltern |
| - | *Tierheim* <code sql> | + | DELETE FROM linie WHERE linien_id |
| - | ALTER TABLE tier | + | |
| - | ADD CONSTRAINT fk_tier_art | + | |
| - | FOREIGN KEY (art_id) REFERENCES tierart(art_id) ON DELETE | + | |
| - | ADD CONSTRAINT fk_tier_gehege | + | |
| - | FOREIGN KEY (gehege_id) REFERENCES gehege(gehege_id) ON DELETE RESTRICT ON UPDATE RESTRICT; </ | + | |
| - | *Postzustellung* <code sql> | + | -- C) UPDATE FK im Kind |
| - | ALTER TABLE briefkasten | + | UPDATE |
| - | ADD CONSTRAINT fk_briefkasten_gebiet | + | |
| - | FOREIGN KEY (gebiet_id) REFERENCES postgebiet(gebiet_id) ON DELETE RESTRICT ON UPDATE | + | |
| - | ALTER TABLE poestler | + | -- D) UPDATE |
| - | ADD CONSTRAINT fk_poestler_gebiet | + | UPDATE linie SET linien_id = 10 WHERE linien_id = 9; -- scheitert bei referenzierten Zeilen |
| - | FOREIGN KEY (gebiet_id) REFERENCES postgebiet(gebiet_id) ON DELETE RESTRICT ON UPDATE | + | </code> |
| + | </WRAP> | ||
| - | *Online-Kleidershop* <code sql> | ||
| - | ALTER TABLE kleidungsstueck | ||
| - | ADD CONSTRAINT fk_kleid_kategorie | ||
| - | FOREIGN KEY (kategorie_id) REFERENCES kategorie(kategorie_id) ON DELETE RESTRICT ON UPDATE RESTRICT, | ||
| - | ADD CONSTRAINT fk_kleid_marke | ||
| - | FOREIGN KEY (marke_id) REFERENCES marke(marke_id) ON DELETE RESTRICT ON UPDATE RESTRICT; </ | ||
| - | *Eishockeyverein* <code sql> | + | === Case: Schweizer Regionen |
| - | ALTER TABLE block | + | |
| - | ADD CONSTRAINT fk_block_team | + | |
| - | FOREIGN KEY (team_id) REFERENCES team(team_id) ON DELETE RESTRICT ON UPDATE RESTRICT; | + | |
| - | ALTER TABLE spieler | + | **FK:** // |
| - | ADD CONSTRAINT fk_spieler_block | + | |
| - | FOREIGN KEY (block_id) REFERENCES block(block_id) ON DELETE RESTRICT ON UPDATE RESTRICT; | + | |
| - | ALTER TABLE team | + | **Daten** |
| - | ADD CONSTRAINT fk_team_trainer | + | <WRAP center box 80% round> |
| - | FOREIGN KEY (trainer_id) REFERENCES trainer(trainer_id) ON DELETE SET NULL ON UPDATE RESTRICT; -- optional | + | <code sql> |
| + | INSERT INTO kanton | ||
| + | (2,' | ||
| + | INSERT INTO gemeinde (gemeinde_id, | ||
| + | VALUES (10001,' | ||
| + | </code> | ||
| + | </WRAP> | ||
| - | *Öffentlicher Verkehr | + | **Tests A–D** |
| - | ALTER TABLE haltestelle | + | <WRAP center box 80% round>< |
| - | ADD CONSTRAINT | + | -- A) INSERT |
| - | FOREIGN KEY (linie_id) REFERENCES | + | INSERT INTO gemeinde |
| + | 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 | ||
| + | </ | ||
| + | </ | ||
| + | |||
| + | ==== 4) (Optional) SET NULL oder CASCADE bewusst einsetzen ==== | ||
| + | Falls in **eurem Modell** eine Beziehung **optional** ist (FK darf NULL sein), könnt ihr '' | ||
| + | |||
| + | <code sql> | ||
| + | ALTER TABLE < | ||
| + | ADD CONSTRAINT | ||
| + | FOREIGN KEY (< | ||
| + | | ||
| + | | ||
| + | | ||
| + | </ | ||
| + | |||
| + | // | ||
| + | |||
| + | **CASCADE** verwenden wir bevorzugt bei **Zwischentabellen** (N:M). | ||
| + | Falls euer Case eine N: | ||
| + | Für reine 1: | ||
| + | |||
| + | ==== 5) Abgabe (pro Gruppe) ==== | ||
| + | |||
| + | **Kurz-Beschrieb (Word-Dokument oder PDF, max. 1 Seite)** mit: | ||
| + | * ERD (Crow’s Foot) mit PK/FK markiert. | ||
| + | * Liste eurer **ALTER TABLE**-Befehle (FK-Namen, ON DELETE/ | ||
| + | * 3–5 **DML-Beispiele** (INSERT/ | ||
| - | ALTER TABLE fahrt | ||
| - | ADD CONSTRAINT fk_fahrt_linie | ||
| - | FOREIGN KEY (linie_id) REFERENCES linie(linie_id) ON DELETE RESTRICT ON UPDATE RESTRICT; </ | ||
| - | *Schweizer Regionen* <code sql> | ||
| - | ALTER TABLE gemeinde | ||
| - | ADD CONSTRAINT fk_gemeinde_kanton | ||
| - | FOREIGN KEY (kanton_code) REFERENCES kanton(kanton_code) ON DELETE RESTRICT ON UPDATE RESTRICT, | ||
| - | ADD CONSTRAINT fk_gemeinde_kva | ||
| - | FOREIGN KEY (kva_id) REFERENCES kva(anlage_id) ON DELETE RESTRICT ON UPDATE RESTRICT; </ | ||