SQL Grundlagen Schulung – Kursbezug
Worum geht’s?
- Was bedeutet „relational“ (Tabellen/Relationen)?
- Warum brauchen wir Primärschlüssel und Fremdschlüssel?
- Wie modelliert man Beziehungen (1:1, 1:n, n:m)?
- Was sind Constraints und warum sind sie wichtig?
SQL-Denkmodell
- Tabelle = Menge von Zeilen (Records).
- Spalte = Attribut (z. B. „ort“, „dauer_tage“).
- Schlüssel = eindeutige Identifikation + Verknüpfung.
- JOIN funktioniert, weil Schlüsselbeziehungen existieren.
Merksatz: „Datenmodell zuerst“. Gute Abfragen sind oft Folge eines sauberen Modells.
Beispiel-Modell (Schulungskontext)
-- Beispiel: Kurs-Termine und Buchungen (konsistent zu Kap. 02–04)
CREATE TABLE kurse (
kurs_id INTEGER PRIMARY KEY,
kurs_name TEXT NOT NULL
);
CREATE TABLE termine (
termin_id INTEGER PRIMARY KEY,
kurs_id INTEGER NOT NULL,
start_datum DATE NOT NULL,
ort TEXT NOT NULL,
format TEXT NOT NULL CHECK (format IN ('Online','Praesenz')),
dauer_tage INTEGER NOT NULL CHECK (dauer_tage > 0),
preis_eur NUMERIC NOT NULL CHECK (preis_eur >= 0),
-- Fremdschlüssel: Termin gehört zu genau einem Kurs
FOREIGN KEY (kurs_id) REFERENCES kurse(kurs_id)
);
CREATE TABLE buchungen (
buchung_id INTEGER PRIMARY KEY,
termin_id INTEGER NOT NULL,
name TEXT NOT NULL,
email TEXT NOT NULL,
created_at TEXT DEFAULT CURRENT_TIMESTAMP,
-- Fremdschlüssel: Buchung gehört zu genau einem Termin
FOREIGN KEY (termin_id) REFERENCES termine(termin_id)
);Beziehungen: 1:n und n:m
1:n (Kurs → Termine)
- Ein Kurs hat viele Termine.
- Ein Termin gehört zu genau einem Kurs.
- Umsetzung: FK
termine.kurs_id→kurse.kurs_id
n:m (Teilnehmende ↔ Termine)
- Ein Teilnehmender kann mehrere Termine buchen.
- Ein Termin hat viele Teilnehmende.
- Umsetzung: Zwischentabelle (z. B.
buchungen)
Warum braucht man IDs?
- Namen sind nicht eindeutig („Max Müller“).
- Texte ändern sich (Rechtschreibfehler, Umzug).
- IDs sind stabil und schnell verknüpfbar (Index/Join).
Constraints: Datenqualität im Modell
- NOT NULL: Pflichtfelder (z. B.
start_datum). - CHECK: Wertebereich (z. B.
dauer_tage > 0). - UNIQUE: Eindeutigkeit (z. B.
emailpro Termin – je nach Regel). - FOREIGN KEY: Referenz muss existieren (keine „Geister-Termins“).
-- Beispiel: E-Mail darf pro Termin nur einmal buchen (optional)
CREATE UNIQUE INDEX ux_buchungen_termin_email
ON buchungen(termin_id, email);
-- Beispiel: Index auf Foreign Key-Spalte für Join-Performance
CREATE INDEX ix_termine_kurs_id
ON termine(kurs_id);Normalisierung (kurz & praxisnah)
- 1NF: keine Listen in einer Spalte („tags“ als CSV), sondern strukturierte Zeilen.
- 2NF/3NF: Attribute gehören dorthin, wo sie logisch „zu Hause“ sind (Kursname nicht in
termineduplizieren).
Anti-Pattern: „Alles in eine Tabelle“
-- SCHLECHT (Beispiel): Kursname wird in jedem Termin wiederholt
CREATE TABLE termine_schlecht (
termin_id INTEGER PRIMARY KEY,
kurs_name TEXT NOT NULL, -- Redundanz!
start_datum DATE NOT NULL,
ort TEXT NOT NULL
);
-- Wenn sich kurs_name ändert, müssen viele Zeilen aktualisiert werden.Praxisaufgabe
- Erstelle die Tabellen
kurse,termine,buchungenaus dem Beispiel. - Füge 1 Kurs, 2 Termine und 2 Buchungen ein.
- Überlege: Welche Spalten sollten NOT NULL sein? Wo ist CHECK sinnvoll?
- (Bonus) Lege einen UNIQUE-Index an, der doppelte Buchungen (Termin+E-Mail) verhindert.
Lösungsvorschlag anzeigen
INSERT INTO kurse(kurs_id, kurs_name) VALUES (1, 'SQL Grundlagen Schulung');
INSERT INTO termine(termin_id, kurs_id, start_datum, ort, format, dauer_tage, preis_eur) VALUES
(101, 1, '2026-02-23', 'Hamburg', 'Praesenz', 3, 1428.00),
(102, 1, '2026-03-09', 'remote', 'Online', 3, 1428.00);
INSERT INTO buchungen(buchung_id, termin_id, name, email) VALUES
(1001, 101, 'Max Mustermann', 'max@example.com'),
(1002, 102, 'Erika Musterfrau', 'erika@example.com');Kurz-Takeaways
- Relational = Tabellen + Beziehungen.
- PK identifiziert Zeilen eindeutig, FK verbindet Tabellen.
- Constraints schützen Datenqualität.
- Sauberes Modell erleichtert JOINs, Aggregationen und Updates.