Eltern- und Kindtabellen
Lösung geprüft
Die Aufgabe der heutigen Stunde sind Eltern- und Kindtabellen! Die Begriffe klingen niedlich, meinen aber nur eine Richtung: wer verweist auf wen. Und die Pointe ist, dass eine Tabelle durchaus beides gleichzeitig sein kann.
Anwendung 1: Gegeben seien folgende Relationen (Fremdschlüssel durch FK angezeigt, Primärschlüssel durch PK):
artikel(id, name, preis, lieferant)
lieferanten(id, name, ort_id)
orte(id, postleitzahl, name)
artikel_hat_lieferant(artikel_id, lieferant_id)
warengruppen(id, name)
artikel_hat_warengruppe(artikel_id, warengruppe_id)
Geben Sie an, welche Tabellen Elterntabellen und welche Kindtabellen sind.
Anwendung 2: Gegeben seien folgende Relationen:
kunden(id, name, land_id)
laender(id, name, kontinent_id)
kontinente(id, name)
Geben Sie an, wo hier Elterntabellen und wo Kindtabellen sind.
Die beiden Begriffe
| Elterntabelle | Kindtabelle | |
|---|---|---|
| Wird verwiesen / verweist | auf sie wird verwiesen | sie verweist auf eine andere |
| Enthält | den Primärschlüssel, auf den gezeigt wird | den Fremdschlüssel |
| Merksatz | Muss zuerst da sein | Kann nur existieren, wenn die Eltern da sind |
Der Merksatz in der letzten Zeile ist der praktisch wichtigste: man kann keinen Artikel mit Lieferant 5 anlegen, bevor es den Lieferanten 5 gibt. Und deshalb muss man die Tabellen auch in dieser Reihenfolge anlegen – erst die Eltern, dann die Kinder. Beim Löschen genau andersherum.
Anwendung 1 – Der Warenbestand
| Tabelle | Verweist auf | Es wird verwiesen von | Rolle |
|---|---|---|---|
orte | – | lieferanten | nur Eltern |
warengruppen | – | artikel_hat_warengruppe | nur Eltern |
lieferanten | orte | artikel, artikel_hat_lieferant | beides |
artikel | lieferanten | artikel_hat_lieferant, artikel_hat_warengruppe | beides |
artikel_hat_lieferant | artikel, lieferanten | – | nur Kind |
artikel_hat_warengruppe | artikel, warengruppen | – | nur Kind |
orte
^
| ort_id
lieferanten <---------+
^ |
| lieferant | lieferant_id
artikel <-------------+
^ artikel_hat_lieferant
| artikel_id
artikel_hat_warengruppe
|
| warengruppe_id
v
warengruppen
erDiagram
orte ||--o{ lieferanten : "ort_id"
lieferanten ||--o{ artikel : "lieferant"
artikel ||--o{ artikel_hat_lieferant : "artikel_id"
lieferanten ||--o{ artikel_hat_lieferant : "lieferant_id"
artikel ||--o{ artikel_hat_warengruppe : "artikel_id"
warengruppen ||--o{ artikel_hat_warengruppe : "warengruppe_id"
orte {
int id PK
string postleitzahl
string name
}
lieferanten {
int id PK
string name
int ort_id FK
}
artikel {
int id PK
string name
decimal preis
int lieferant FK
}
artikel_hat_lieferant {
int artikel_id PK, FK
int lieferant_id PK, FK
}
warengruppen {
int id PK
string name
}
artikel_hat_warengruppe {
int artikel_id PK, FK
int warengruppe_id PK, FK
}
lieferanten und artikel sind gleichzeitig
Eltern und Kind. Das ist der Kern der Aufgabe: die Rolle ist nicht die
Eigenschaft einer Tabelle, sondern die einer Beziehung.
In der Beziehung zu orte ist lieferanten das
Kind, in der Beziehung zu artikel das Elternteil.
Etwas Merkwürdiges an dieser Datenbank
artikel hat ein Attribut lieferant – und
gleichzeitig gibt es die Tabelle artikel_hat_lieferant. Damit
ist dieselbe Beziehung doppelt abgebildet.
Beides zusammen ergibt keinen Sinn. Entweder hat ein Artikel genau einen
Lieferanten, dann reicht der Fremdschlüssel in artikel und
die Verknüpfungstabelle ist überflüssig. Oder ein Artikel kann von
mehreren Lieferanten kommen, dann braucht man die Verknüpfungstabelle und
das Attribut lieferant muss weg.
So etwas in der Antwort zu erwähnen, kostet nichts und zeigt, dass man den Entwurf wirklich gelesen hat.
Anwendung 2 – Die Kette
kunden(id, name, land_id) land_id ist FK -> laender.id
laender(id, name, kontinent_id) kontinent_id ist FK -> kontinente.id
kontinente(id, name)
| Tabelle | Rolle | Begründung |
|---|---|---|
kontinente | nur Elterntabelle | Hat keinen Fremdschlüssel; laender verweist darauf |
laender | Eltern und Kind | Kind von kontinente, Elternteil von kunden |
kunden | nur Kindtabelle | Verweist auf laender; niemand verweist auf die Kunden |
kontinente (Eltern)
^
| kontinent_id
laender (Kind und Eltern)
^
| land_id
kunden (Kind)
Das ist eine saubere dreistufige Hierarchie. Man kann sie in beide Richtungen lesen: „In welchem Kontinent wohnt Kunde X?" geht über zwei Schritte nach oben. „Welche Kunden wohnen in Europa?" geht über zwei Schritte nach unten.
Warum das praktisch wichtig ist
| Was du tust | Reihenfolge |
|---|---|
| Tabellen anlegen | kontinente → laender → kunden |
| Daten einfügen | kontinente → laender → kunden |
| Daten löschen | kunden → laender → kontinente |
| Tabellen löschen | kunden → laender → kontinente |
Wer versucht, „Europa" aus kontinente zu löschen, während
noch Länder darauf verweisen, bekommt eine Fehlermeldung wegen
referenzieller Integrität. Die Datenbank verhindert
damit, dass Länder mit einem Verweis auf einen Kontinent zurückbleiben,
den es nicht mehr gibt. Solche verwaisten Verweise nennt man
dangling references, und genau die soll es nicht geben.