Modul 4 von 6
Datenbanken und SQL
Wenn du aus diesem ganzen Vorbereitungskurs nur ein Modul richtig gut beherrschen könntest, sollte es dieses sein. SAP-Systeme sind im Kern große Datenbanken, und SQL ist die Sprache, in der man mit ihnen redet. Auf dieser Seite läuft eine echte SQLite-Datenbank direkt in deinem Browser - jede Abfrage, die du tippst, wird wirklich ausgeführt.
Alle Beispiele arbeiten auf demselben kleinen ERP-Datenbestand: Kunden erteilen Aufträge, ein Auftrag besteht aus mehreren Positionen, jede Position verweist auf ein Produkt. Genau dieser Zuschnitt begegnet dir in SAP wieder - dort nur mit ein paar hundert Feldern mehr.
1. Warum überhaupt Datenbanken?
Man könnte Daten auch in Dateien speichern - viele Unternehmen tun das bis heute mit Excel. Bei mehr als einem Benutzer und mehr als ein paar tausend Zeilen bricht das aber zusammen.
| Problem in einer Tabellendatei | Wie eine Datenbank es löst |
|---|---|
| Zwei Leute öffnen die Datei und speichern gleichzeitig - eine Änderung geht verloren | Mehrbenutzerbetrieb mit Sperren und Transaktionen |
| Dieselbe Kundenadresse steht an 40 Stellen, 3 davon veraltet | Jeder Wert steht genau einmal, alles andere verweist darauf |
| Jemand tippt in ein Zahlenfeld „ca. 50“ | Datentypen und Regeln verhindern ungültige Werte |
| Der Rechner stürzt mitten im Speichern ab | Eine Änderung wird ganz oder gar nicht ausgeführt |
| Suchen dauert bei 500 000 Zeilen minutenlang | Indizes finden den Treffer in Millisekunden |
| Jeder kann alles sehen und ändern | Rechte je Benutzer, Tabelle und sogar Spalte |
Die Datenbank ist der Datenbestand selbst. Das Datenbankmanagementsystem (DBMS) ist die Software, die ihn verwaltet - zum Beispiel SAP HANA, PostgreSQL, Oracle oder SQLite. Zusammen bilden sie das Datenbanksystem. In Klausuren wird nach dieser Abgrenzung regelmäßig gefragt.
2. Das relationale Modell
Fast alle Unternehmensdatenbanken sind relational: Die Daten liegen in Tabellen, und die Tabellen sind über Werte miteinander verknüpft.
| Fachbegriff | Alltagswort | Bedeutung |
|---|---|---|
| Relation | Tabelle | eine Sammlung gleichartiger Datensätze |
| Tupel | Zeile / Datensatz | ein einzelner Kunde, ein einzelner Auftrag |
| Attribut | Spalte / Feld | eine Eigenschaft, etwa der Ort |
| Domäne | Wertebereich | welche Werte erlaubt sind, etwa Datum |
Primärschlüssel und Fremdschlüssel
Der Primärschlüssel macht jede Zeile eindeutig identifizierbar. Er darf nie leer sein und nie doppelt vorkommen. Ein Fremdschlüssel ist ein Feld, das auf den Primärschlüssel einer anderen Tabelle zeigt - so entstehen die Verbindungen.
kunden auftraege
┌────────────┬────────────┐ ┌────────────┬───────────┐
│ kunden_id │ name │ │ auftrag_id │ kunden_id │
│ (Primär) │ │ │ (Primär) │ (Fremd) │
├────────────┼────────────┤ ├────────────┼───────────┤
│ 1 │ Meier GmbH │◄────┤ 1 │ 1 │
│ 2 │ Schulz AG │ │ 5 │ 1 │
└────────────┴────────────┘ └────────────┴───────────┘
Auftrag 1 und 5 gehören zu Kunde 1
Die Datenbank wacht darüber, dass ein Fremdschlüssel immer auf eine tatsächlich vorhandene Zeile zeigt. Sie verhindert also, dass man einen Auftrag für Kunde 99 anlegt, wenn es diesen Kunden nicht gibt - und dass man einen Kunden löscht, zu dem noch Aufträge existieren. Das ist keine Schikane, sondern der Schutz davor, dass die Datenbank in einen widersprüchlichen Zustand gerät.
Beziehungsarten
Ein Mitarbeiter hat genau einen Dienstwagen. Selten - meist packt man solche Daten in dieselbe Tabelle.
Ein Kunde hat viele Aufträge, ein Auftrag gehört zu genau einem Kunden. Der Fremdschlüssel steht auf der n-Seite, also beim Auftrag.
Ein Auftrag enthält viele Produkte, ein Produkt kommt in vielen Aufträgen vor. Das lässt sich nicht direkt abbilden.
Man schiebt eine Zwischentabelle ein - hier positionen.
Sie hat zwei Fremdschlüssel und wird so zu zwei 1:n-Beziehungen.
3. ER-Modellierung
Bevor eine Tabelle angelegt wird, zeichnet man das Modell. Das Entity-Relationship-Diagramm zeigt, welche Dinge es gibt und wie sie zusammenhängen - noch ohne technische Details.
- Entität: ein Ding, über das Daten gespeichert werden (Kunde, Produkt)
- Attribut: eine Eigenschaft davon (Name, Preis)
- Beziehung: wie Entitäten zusammenhängen (Kunde erteilt Auftrag)
- Kardinalität: wie viele auf jeder Seite stehen (1:n, n:m)
┌──────────┐ ┌───────────┐ ┌───────────┐
│ KUNDE │ 1 n │ AUFTRAG │ 1 n │ POSITION │
│ ├────────────┤ ├────────────┤ │
│ kunden_id│ erteilt │auftrag_id │ enthält │position_id│
│ name │ │ datum │ │ menge │
│ ort │ │ status │ │ │
└──────────┘ └───────────┘ └─────┬─────┘
│ n
│
┌────┴──────┐
│ PRODUKT │ 1
│produkt_id │
│bezeichnung│
│nettopreis │
└───────────┘
- Text durchlesen und alle Substantive markieren - das sind Kandidaten für Entitäten.
- Verben markieren - daraus werden die Beziehungen.
- Für jede Entität den Primärschlüssel festlegen.
- Kardinalitäten bestimmen: Frag für jede Richtung einzeln "wie viele?".
- Jede n:m-Beziehung durch eine Zwischentabelle auflösen.
4. Normalisierung
Normalisierung ist das systematische Zerlegen von Tabellen, damit jede Information nur an einer einzigen Stelle steht. Klick dich durch die vier Schritte und beobachte, welches Problem dabei jeweils verschwindet.
Die drei Normalformen als Merksatz
Jedes Nichtschlüsselattribut hängt ab vom Schlüssel (1. NF), vom ganzen Schlüssel (2. NF) und von nichts als dem Schlüssel (3. NF).
| Normalform | Bedingung | Verletzt, wenn … |
|---|---|---|
| 1. NF | alle Werte sind atomar | in einer Zelle mehrere Werte stehen, etwa „Schraube, Mutter“ |
| 2. NF | 1. NF und keine Abhängigkeit von einem Teil des Schlüssels | der Schlüssel aus zwei Feldern besteht und ein Attribut nur von einem abhängt |
| 3. NF | 2. NF und keine transitiven Abhängigkeiten | ein Attribut von einem anderen Nichtschlüsselattribut abhängt (Ort hängt am Kunden, nicht am Auftrag) |
Die drei Anomalien
- Einfügeanomalie: Ein neuer Kunde lässt sich nicht anlegen, solange er keinen Auftrag hat.
- Änderungsanomalie: Eine Adressänderung muss an vielen Stellen nachgezogen werden; wird eine vergessen, widersprechen sich die Daten.
- Löschanomalie: Mit dem letzten Auftrag verschwindet auch die Adresse des Kunden.
Normalisierung spart Speicher und verhindert Widersprüche - aber sie erzwingt viele JOINs beim Lesen. In Auswertungssystemen (Data Warehouse, SAP BW) nimmt man deshalb bewusst Redundanz in Kauf, um Berichte schneller zu machen. Das ist kein Fehler, sondern eine Abwägung: normalisieren für das Erfassen, denormalisieren für das Auswerten.
5. SQL: Daten abfragen
SQL (Structured Query Language) ist die Sprache aller relationalen Datenbanken. Das Besondere: Du beschreibst was du willst, nicht wie es geholt werden soll. Den Weg sucht sich die Datenbank selbst.
SELECT spalten -- welche Spalten sollen erscheinen
FROM tabelle -- woher
WHERE bedingung -- welche Zeilen
GROUP BY spalte -- zusammenfassen nach
HAVING bedingung -- Filter auf die Gruppen
ORDER BY spalte -- Sortierung
LIMIT anzahl; -- nur die ersten n
Geschrieben wird SELECT zuerst, ausgeführt wird es fast zuletzt. Die
Datenbank arbeitet in dieser Reihenfolge:
FROM → WHERE → GROUP BY → HAVING → SELECT → ORDER BY → LIMIT.
Daraus folgt der wichtigste praktische Merksatz:
WHERE filtert einzelne Zeilen, HAVING filtert fertige Gruppen.
Probier es aus
Unten steht eine echte Datenbank. Ändere die Abfrage und drück auf Ausführen - Strg+Eingabe geht auch.
Die wichtigsten WHERE-Bedingungen
| Schreibweise | Bedeutung |
|---|---|
= <> < > <= >= | Vergleiche. Ungleich ist <>, nicht != |
BETWEEN 10 AND 20 | Bereich, Grenzen eingeschlossen |
IN ('DE', 'AT') | einer aus einer Liste |
LIKE 'Meier%' | Textmuster; % steht für beliebig viele Zeichen |
IS NULL | Feld ist leer |
AND OR NOT | Bedingungen verknüpfen |
NULL bedeutet „unbekannt“. Deshalb ergibt WHERE betreuer = NULL
nie einen Treffer - denn unbekannt ist auch nicht gleich unbekannt. Richtig
ist WHERE betreuer IS NULL. Das ist einer der häufigsten SQL-Fehler
überhaupt, und in Klausuren eine gern gestellte Fangfrage. Probier es unten aus:
In der Tabelle kunden gibt es genau einen Kunden ohne Betreuer.
6. SQL: Tabellen verknüpfen
Weil normalisierte Daten über mehrere Tabellen verteilt sind, muss man sie zum Lesen wieder zusammenführen. Das macht der JOIN.
SELECT k.name, a.auftrag_id, a.datum
FROM kunden k
JOIN auftraege a ON a.kunden_id = k.kunden_id;
-- └──────────┬──────────┘
-- die Verbindungsbedingung:
-- welcher Fremdschlüssel zeigt auf welchen Primärschlüssel
- INNER JOIN (oder einfach JOIN): nur Zeilen, die auf beiden Seiten einen Partner haben. Der Normalfall.
- LEFT JOIN: alle Zeilen der linken Tabelle, auch ohne Partner - fehlende Werte werden zu NULL.
- RIGHT JOIN: dasselbe umgekehrt.
- FULL OUTER JOIN: alles von beiden Seiten.
Frage: „Wie viele Aufträge hat jeder Kunde?“ Mit INNER JOIN tauchen Kunden ohne Aufträge gar nicht auf - die Antwort ist unvollständig, und niemand merkt es. Mit LEFT JOIN erscheinen sie mit dem Wert 0. Immer wenn die Frage „alle X, auch die ohne Y“ lautet, brauchst du einen LEFT JOIN.
Aufgabe: drei Tabellen verbinden
Zeig für jeden Auftrag die Auftragsnummer, den Kundennamen und die
Produktbezeichnung jeder Position. Du brauchst dafür alle vier Tabellen außer
mitarbeiter.
Lösung anzeigen
SELECT a.auftrag_id, k.name, p.bezeichnung
FROM auftraege a
JOIN kunden k ON k.kunden_id = a.kunden_id
JOIN positionen po ON po.auftrag_id = a.auftrag_id
JOIN produkte p ON p.produkt_id = po.produkt_id;
Denkweise: Man hangelt sich an den Fremdschlüsseln entlang. Vom Auftrag
kommt man zum Kunden (über kunden_id) und zu den Positionen (über
auftrag_id); von der Position zum Produkt (über
produkt_id). Die kurzen Buchstaben hinter den Tabellennamen sind
Aliase - ohne sie wird die Abfrage schnell unleserlich.
7. SQL: Gruppieren und auswerten
Hier wird SQL zum Werkzeug für Auswertungen - genau das, was im Berufsalltag der Wirtschaftsinformatik den größten Teil ausmacht.
| Funktion | Was sie tut |
|---|---|
COUNT(*) | zählt Zeilen |
SUM(spalte) | summiert |
AVG(spalte) | Durchschnitt |
MIN / MAX | kleinster und größter Wert |
ROUND(wert, 2) | rundet auf 2 Nachkommastellen |
COUNT(*) zählt alle Zeilen. COUNT(betreuer) zählt nur die
Zeilen, in denen dieses Feld nicht NULL ist. Der Unterschied fällt erst auf,
wenn Daten fehlen - und dann stimmt der Bericht nicht mehr.
FROMundJOINführen Kunden, Aufträge und Positionen zu einer breiten Tabelle zusammen.WHEREwirft stornierte Aufträge heraus - vor dem Gruppieren, sie zählen also nirgends mit.GROUP BYfasst alle Zeilen eines Kunden zu einer zusammen.SUMundCOUNTrechnen innerhalb jeder Gruppe.DISTINCTist nötig, weil dieselbe Auftragsnummer durch die Positionen mehrfach vorkommt.HAVINGfiltert die fertigen Gruppen - das ginge mit WHERE nicht, weil die Summe dort noch gar nicht existiert.
Aufgabe: Umsatz je Produktkategorie
Ermittle je kategorie den Gesamtumsatz (Menge mal Einzelpreis) über alle
Positionen, absteigend sortiert. Nenn die Summenspalte umsatz.
Lösung anzeigen
SELECT p.kategorie,
ROUND(SUM(po.menge * po.einzelpreis), 2) AS umsatz
FROM positionen po
JOIN produkte p ON p.produkt_id = po.produkt_id
GROUP BY p.kategorie
ORDER BY umsatz DESC;
Die Regel zu GROUP BY: Jede Spalte, die im SELECT steht und nicht in einer Aggregatfunktion wie SUM steckt, muss im GROUP BY auftauchen. Sonst wüsste die Datenbank nicht, welchen der vielen Werte einer Gruppe sie anzeigen soll.
Unterabfragen
Eine Abfrage darf innerhalb einer anderen stehen. Damit beantwortet man Fragen, die sich auf ein Zwischenergebnis beziehen - etwa „alle Produkte, die teurer sind als der Durchschnitt“.
8. Daten ändern, Transaktionen und ACID
Die drei ändernden Befehle
INSERT INTO kunden (kunden_id, name, ort, land, kunde_seit, betreuer)
VALUES (13, 'Nova Systems', 'Leipzig', 'DE', '2025-01-15', 1);
UPDATE produkte
SET nettopreis = nettopreis * 1.05
WHERE kategorie = 'Antrieb';
DELETE FROM auftraege
WHERE status = 'storniert';
Ohne WHERE gilt ein UPDATE oder DELETE für alle Zeilen der
Tabelle. DELETE FROM kunden; leert die gesamte Kundentabelle - ohne
Nachfrage. Angewohnheit, die dich einmal retten wird: Schreib die Anweisung
zuerst als SELECT mit demselben WHERE, sieh dir an, welche Zeilen betroffen
wären, und tausch dann SELECT gegen UPDATE oder DELETE. Auf dieser Seite ist das
gefahrlos - die Datenbank wird bei jedem Ausführen neu aufgebaut.
Transaktionen
Eine Transaktion fasst mehrere Anweisungen zu einer Einheit zusammen, die entweder komplett oder gar nicht ausgeführt wird.
Konto A wird belastet, Konto B bekommt gutgeschrieben. Fällt der Server zwischen den beiden Schritten aus, ist das Geld verschwunden. Eine Transaktion verhindert das: Entweder passieren beide Buchungen oder keine.
ACID - vier Buchstaben, die du auswendig können solltest
| Buchstabe | Bedeutung | Was es garantiert |
|---|---|---|
| A | Atomarität | Alles oder nichts - halbe Transaktionen gibt es nicht. |
| C | Konsistenz | Vorher und nachher gelten alle Regeln, etwa Fremdschlüssel. |
| I | Isolation | Parallele Transaktionen stören sich nicht gegenseitig. |
| D | Dauerhaftigkeit | Was bestätigt wurde, überlebt auch einen Stromausfall. |
Indizes
Ein Index ist eine zusätzliche sortierte Struktur über einer Spalte -
wie das Stichwortverzeichnis hinten im Buch. Ohne Index muss die Datenbank die ganze
Tabelle lesen (O(n)), mit Index findet sie den Treffer in
O(log n).
Jeder Index muss bei jedem INSERT, UPDATE und DELETE mitgepflegt werden. Indizes machen also das Lesen schneller und das Schreiben langsamer, und sie brauchen Speicher. Faustregel: Spalten indizieren, nach denen häufig gefiltert oder sortiert wird - Primär- und Fremdschlüssel bekommen ihn meist automatisch. Das ist genau die Abwägung aus Modul 3.
SQL-Übungen
Jede Aufgabe wird automatisch geprüft: Deine Abfrage wird mit einer Musterlösung verglichen. Der Weg ist egal - es zählt nur, dass dasselbe Ergebnis herauskommt.
Aufgabe 1 · leicht
Zeig alle Produkte der Kategorie Steuerung mit Bezeichnung und Preis,
sortiert nach Preis absteigend.
Aufgabe 2 · leicht
Wie viele Kunden gibt es je Land? Zwei Spalten: land und
anzahl.
Aufgabe 3 · mittel
Zeig alle Kunden, deren Name mit W beginnt oder die in Berlin sitzen.
Aufgabe 4 · mittel
Ermittle für jeden Betreuer aus der Tabelle mitarbeiter, wie viele Kunden
er betreut. Spalten: name und kundenzahl. Auch Mitarbeiter
ohne Kunden sollen erscheinen - überleg, welche JOIN-Art du dafür brauchst.
Lösung anzeigen
SELECT m.name, COUNT(k.kunden_id) AS kundenzahl
FROM mitarbeiter m
LEFT JOIN kunden k ON k.betreuer = m.mitarbeiter_id
GROUP BY m.mitarbeiter_id, m.name;
Zwei Feinheiten: Der LEFT JOIN sorgt dafür, dass auch Mitarbeiter aus
Support und Einkauf erscheinen - mit 0. Und es muss
COUNT(k.kunden_id) heißen, nicht COUNT(*): Bei einem
Mitarbeiter ohne Kunden entsteht durch den LEFT JOIN eine Zeile mit lauter NULL,
die COUNT(*) als 1 zählen würde. COUNT(spalte)
überspringt NULL und liefert korrekt 0.
Aufgabe 5 · schwer
Welche drei Produkte haben den höchsten Gesamtumsatz (Menge mal Einzelpreis über alle
Positionen)? Spalten: bezeichnung und umsatz, absteigend,
nur die obersten drei.
Lösung anzeigen
SELECT p.bezeichnung,
ROUND(SUM(po.menge * po.einzelpreis), 2) AS umsatz
FROM positionen po
JOIN produkte p ON p.produkt_id = po.produkt_id
GROUP BY p.produkt_id, p.bezeichnung
ORDER BY umsatz DESC
LIMIT 3;
Gruppiert wird nach produkt_id und nicht nur nach der Bezeichnung -
falls zwei Produkte einmal gleich heißen, bleiben sie so trotzdem getrennt. Bei
Auswertungen immer nach dem Schlüssel gruppieren, nicht nach dem Anzeigetext.
Selbsttest
Karteikarten zu diesem Modul
Wenn du tiefer einsteigen willst
- sqlbolt.com und SQLZoo - interaktive SQL-Kurse, beide kostenlos. Ideal, wenn du nach diesem Modul einfach weiterüben willst.
- "SQL - der Grundkurs" von Ralf Adams - deutschsprachig und praxisnah.
- openSAP - SAP bietet kostenlose Onlinekurse an, unter anderem zu HANA und zur Datenmodellierung. Ein Kurs vor Studienbeginn macht sich im Gespräch mit Kollegen gut bezahlt.