⚠ Hinweis zur Datenqualität: Die Daten dieser Seite wurden durch manuelle Analyse aller SQL-Datenbankaufgaben aus den offiziellen Prüfungsvorschlägen gewonnen und mithilfe von KI ausgewertet. Trotz sorgfältiger Prüfung können einzelne Einträge fehlerhaft oder unvollständig sein. Im Zweifelsfall mit den offiziellen Prüfungsunterlagen vergleichen.
⚠ Wichtiger Hinweis zur Vollständigkeit: Dieses Dokument beschreibt syntaktische und logische SQL-Muster, die direkt aus den Aufgabentexten und Musterlösungen ableitbar sind. Konkrete Tabellen- und Spaltennamen kommen immer aus dem Relationen-Modell bzw. ER-Diagramm der jeweiligen Aufgabe — diese musst du selbst aus den Aufgabenunterlagen entnehmen. Stellen, an denen ein konkreter Wert aus dem Diagramm benötigt wird, sind mit [→ DIAGRAM] markiert.

1 · Aufgabentypen — Übersicht

Alle wiederkehrenden SQL-Aufgabenformen aus 10 Jahren Abitur, mit Häufigkeit und Erkennungsmerkmal.
Aufgabentyp Schlüsselwörter im Aufgabentext SQL-Befehl Häufigkeit
Neuen Datensatz einfügen neu, wird aufgenommen, wird hinzugefügt, wird in die Datenbank eingetragen, erstmalig INSERT INTO sehr hoch
Datensatz aktualisieren soll aktualisiert werden, wird übernommen, erhöhen um X%, wird auf … gesetzt, bekommt … zugeteilt, fälschlicherweise UPDATE … SET sehr hoch
Einfache Auswahlabfrage ermitteln, ausgeben, anzeigen, auflisten — mit Filterbedingung aus einer Tabelle SELECT … WHERE sehr hoch
Mehrere Tabellen verknüpfen Ausgabe enthält Spalten aus mindestens 2 Tabellen (z.B. Name + Vertragsnummer) SELECT … JOIN / FROM t1, t2 WHERE sehr hoch
Aggregation & Gruppierung Anzahl, Summe, je … die Summe, gruppiert nach, die mehr als X … haben COUNT/SUM + GROUP BY + HAVING sehr hoch
Sortierung + Top-N-Begrenzung sortiert, die drei … mit dem höchsten, die letzten zehn, nur N … anzeigen ORDER BY + LIMIT hoch
LEFT JOIN — auch ohne Treffer auch … die noch keine … haben, alle … auch die ohne, auch Rechnungen, für die keine Zahlungen vorliegen LEFT JOIN hoch
Unterabfrage — Ausschluss die noch nie, die keinen … haben, für die keine … vorliegen, die noch nicht WHERE … NOT IN (SELECT …) hoch
Unterabfrage — Vergleich mit Aggregat über dem Durchschnitt, mindestens so viele wie, nur wenn … mehr als X WHERE x > (SELECT AVG(…)) mittel
Datensatz löschen (einfach) soll gelöscht werden, soll entfernt werden — mit bereits bereinigten Abhängigkeiten DELETE FROM … WHERE mittel
Löschen mit referentieller Integrität unter Berücksichtigung der referentiellen Integrität, keine kaskadierende Löschung mehrere DELETE + Reihenfolge mittel
Datumsfunktionen im Monat Januar, im vergangenen Jahr, aktuelles Datum, Differenz in Minuten NOW(), YEAR(), MONTH(), LIKE '…%' mittel
Tabelle erstellen / erweitern Tabelle … soll in der Datenbank ergänzt werden, Fremdschlüssel … ergänzen CREATE TABLE + ALTER TABLE selten
SQL-Anweisung erläutern Erläutern Sie den Aufbau und die inhaltliche Bedeutung — (Text) selten
MySQL-Variable SET @var Hinweis im Aufgabentext: SET @variablenName = (SELECT … FROM …); SET @var = … selten

2 · INSERT INTO — Neuen Datensatz einfügen

Häufigster DML-Schreibbefehl. Immer wenn etwas „neu" ist oder „aufgenommen" / „eingetragen" werden soll.
Goldene Regel: Das Wort „neu" im Aufgabentext bedeutet fast immer INSERT INTO — auch wenn die Person oder das Objekt im weiteren Satz so beschrieben wird, als existiere sie schon. Lies: „Der neue Mitarbeiter Max Müller übernimmt ab sofort …" → zuerst INSERT, dann ggf. UPDATE/weitere Verknüpfungen.

2.1 Einfaches INSERT

Erkennungsmerkmal: Alle Werte sind direkt im Aufgabentext angegeben
Alle einzufügenden Werte werden explizit im Text genannt (Name, Datum, Preis, …). Kein Nachschlagen anderer Tabellen nötig.
Variante mit Spaltenliste: Wenn nicht alle Spalten befüllt werden (z.B. IBAN noch nicht bekannt), Spalten explizit angeben.
INSERT — alle Werte bekannt (ABI 2017 B, ABI 2024 B)
-- Alle Spalten werden befüllt (Reihenfolge = Tabellendefinition) INSERT INTO Fahrzeugklasse VALUES ("Van", 0.15, 0.25); -- Nicht alle Spalten bekannt → Spalten explizit nennen (IBAN fehlt) INSERT INTO Fahrer (fahrernr, nachname, vorname, stundenlohn) VALUES (333, 'Knebel', 'Lennard', 12.0); -- → iban wird implizit NULL (wenn die Spalte das erlaubt)

2.2 INSERT mit AUTO_INCREMENT

Erkennungsmerkmal: „Die ID/Nummer wird vom System automatisch vergeben"
Wenn der Hinweis „AUTO_INCREMENT" oder „wird automatisch vergeben" erscheint, darf der Primärschlüssel beim INSERT weggelassen werden — entweder durch explizite Spaltenliste (ohne PK) oder NULL als Platzhalterwert.
INSERT mit AUTO_INCREMENT — PK weglassen (ABI 2021 A, ABI 2022 A, ABI 2022 C)
-- PK (bestellNr) wird automatisch vergeben → aus Spaltenliste weglassen INSERT INTO Bestellung (bestellDatum, kNr) VALUES ('2022-05-02', 7654); -- Alternativ: NULL als Platzhalterwert für AUTO_INCREMENT INSERT INTO Geschaeftsfuehrer (vorname, nachname) VALUES ('Mira', 'Bellenbaum'); -- → personalnr wird automatisch vergeben (z.B. 1, 2, 3, ...)

2.3 INSERT mit Unterabfrage (FK-Wert unbekannt)

Erkennungsmerkmal: Fremdschlüssel-Wert ist nicht direkt im Text gegeben
Wenn ein Fremdschlüssel (z.B. fgid einer Fluggesellschaft, gid eines Genres) eingefügt werden muss, aber nur der Name im Aufgabentext steht, muss der Wert per SELECT-Unterabfrage ermittelt werden.
Erkennbar auch am Hinweis: „Die Primärschlüssel von X und Y sind zu ermitteln."
INSERT mit Unterabfrage für FK-Werte (ABI 2021 B, ABI 2022 C, ABI 2023 B)
-- FK-Werte vid und gid sind unbekannt → per Unterabfrage ermitteln INSERT INTO Film (fid, titel, osprache, fsk, laenge, vid, gid) VALUES (4723, 'Logo Movie', 'English', 0, 145, (SELECT vid FROM Verleih WHERE name = 'Logo Movie Production'), (SELECT gid FROM Genre WHERE bezeichnung = 'Animation') );

2.4 Mehrstufiges INSERT (verkettete Abhängigkeiten)

Erkennungsmerkmal: Neuer Kunde + neue Bestellung + neue Position (+ Bestandsaktualisierung)
Wenn eine neue Person und gleichzeitig eine erste Bestellung/Buchung/Verknüpfung angelegt werden soll, braucht man mehrere INSERT-Anweisungen in FK-Reihenfolge (Elterntabelle zuerst). Häufig wird danach noch ein UPDATE benötigt (z.B. Bestand verringern).

Typische Kette: INSERT Kunde → INSERT Bestellung → INSERT Position → UPDATE Bestand
Mehrstufiges INSERT mit FK-Abhängigkeit (ABI 2022 A)
-- Schritt 1: Kunde einfügen INSERT INTO Kunde (kNr, vname, nname, plz, ort, strasse, telefon) VALUES (7654, 'Hans', 'Hecht', '89075', 'Ulm', 'Donautor 1', '0177 1234567'); -- Schritt 2: Bestellung einfügen (AUTO_INCREMENT für bestellNr) INSERT INTO Bestellung (bestellDatum, kNr) VALUES ('2022-05-02', 7654); -- Schritt 3: Position einfügen — bestellNr per Unterabfrage ermitteln INSERT INTO Position VALUES ((SELECT bestellNr FROM Bestellung WHERE bestellDatum = '2022-05-02' AND kNr = 7654), 277, 1); -- Schritt 4: Artikelbestand verringern UPDATE Artikel SET bestand = bestand - 1 WHERE artNr = 277;
Reihenfolge ist entscheidend! Elterntabellen (ohne FK auf andere) immer zuerst befüllen. Kindtabellen (mit FK auf Eltern) danach. Falsche Reihenfolge → Integritätsfehler. Tipp: Beim Lesen des Relationen-Modells die FK-Pfeile (#-Markierung) zurückverfolgen.

3 · UPDATE — Datensatz aktualisieren

Tritt auf wenn bestehende Daten geändert werden sollen — Preis, Zuweisung, Ersetzung, Berechnung.

3.1 Einfaches UPDATE mit bekannter WHERE-Bedingung

Erkennungsmerkmal: Konkreter Wert und klare Bedingung im Text
Wenn ein konkreter Wert (z.B. Produktname, ID, Klasse) als Bedingung gegeben ist und ein Feld direkt gesetzt werden soll.
UPDATE einfach — direkter Wert (ABI 2016 B, ABI 2025 B)
-- Klassenlehrer wechseln (ID direkt bekannt) UPDATE klasse SET persNr_kl = 101702 WHERE klBezeichnung = '10a' AND klSchuljahr = '2014/15'; -- Produktname ändern UPDATE Getraenk SET bezeichnung = 'Hessen Cola' WHERE bezeichnung = 'Fratz Cola';

3.2 UPDATE mit relativer Berechnung (Preis / Bestand)

Erkennungsmerkmal: „um X% erhöhen", „um 1 verringern", „wird überschrieben"
Der neue Wert ergibt sich aus dem alten Wert durch eine Rechenoperation. Das SET referenziert die Spalte selbst.
-- Preis um 5% erhöhen UPDATE Komponente SET preis = preis * 1.05 WHERE hersteller = 'MANU'; -- Preis um 15% erhöhen UPDATE Artikel SET vkpreis = vkpreis * 1.15 WHERE typ = 'Badetuch'; -- Bestand um 1 verringern UPDATE Artikel SET istBestand = istBestand - 1 WHERE artNr = 277; -- Kettenwerte: alter Zählerstand → vorherigen Wert, neuer → konkreten Wert UPDATE Vertrag SET verbrauch_vorjahr = (zaehlerstand_neu - zaehlerstand_alt), zaehlerstand_alt = zaehlerstand_neu, zaehlerstand_neu = 9999 WHERE zaehlernummer = 123456;
Reihenfolge der SET-Spalten bei Kettenwerten: Wenn ein Feldwert (z.B. zaehlerstand_neu) gleichzeitig als Quelle und als Ziel verwendet wird, beachten — MySQL wertet alle rechten Seiten vor dem Schreiben aus. Die Reihenfolge der Felder im SET spielt keine Rolle für das Ergebnis, solange man die Logik korrekt modelliert.

3.3 UPDATE mit Unterabfrage (FK-Wert unbekannt)

Erkennungsmerkmal: „wird von [Name] übernommen" — ID von Person/Objekt nicht direkt gegeben
Wenn eine Zuweisung geändert werden soll und der neue Wert (Fremdschlüssel) erst über eine andere Tabelle ermittelt werden muss — z.B. „Tim Weiss übernimmt alle Buchungen".
UPDATE mit Unterabfrage für neuen Wert (ABI 2016 B, ABI 2018 B, ABI 2024 B)
-- Neuer Fahrer (Name bekannt, ID unbekannt) übernimmt Einsätze UPDATE Einsatz SET fahrerNr = (SELECT fahrerNr FROM Fahrer WHERE nachname = 'Tischendorf' AND vorname = 'Tobias') WHERE fahrerNr = 333 AND beginn BETWEEN '2023-05-01' AND '2023-05-14';

3.4 Mehrtabellen-UPDATE (MySQL-spezifisch)

Erkennungsmerkmal: Mehrere Tabellen müssen gleichzeitig aktualisiert werden
MySQL erlaubt UPDATE tabelle1, tabelle2 SET … WHERE … — nützlich wenn ein Wert in Tabelle A von einem Wert in Tabelle B abhängt und man kein zweistufiges UPDATE verwenden möchte.
-- Kontostand aller zahlungsfähigen Darlehenskunden abziehen (ABI 2022 B) UPDATE Girokonto g, Darlehen d SET g.kontostand = g.kontostand - d.rate WHERE d.referenzkonto = g.iban AND d.turnus = 12 AND g.kontostand - d.rate >= 0;

4 · DELETE — Datensatz löschen

Kritisches Muster: Referentielle Integrität beachten! Kindtabellen zuerst löschen, dann die Elterntabelle.

4.1 Einfaches DELETE

Erkennungsmerkmal: „soll gelöscht werden" — Abhängigkeiten wurden bereits bereinigt
Wenn die Aufgabe explizit erwähnt, dass abhängige Datensätze bereits entfernt wurden oder keine bestehen.
DELETE FROM rechnung WHERE rechnr = 4743;

4.2 DELETE mit referentieller Integrität (mehrstufig)

Erkennungsmerkmal: „referentielle Integrität", „keine kaskadierende Löschung" im Hinweis
Wenn ausdrücklich auf referentielle Integrität hingewiesen wird, müssen alle abhängigen Tabellen in umgekehrter FK-Reihenfolge zuerst bereinigt werden. Strategie: Im Relationen-Modell nachschauen, welche Tabellen einen FK auf die zu löschende Tabelle haben → diese zuerst löschen.
Mehrstufiges DELETE — Bestellung mit allen Abhängigkeiten löschen (ABI 2025 A)
-- Schritt 0: Zu löschende bID per Variable ermitteln (Hinweis im Aufgabentext) SET @bestellung = (SELECT bID FROM Bestellung ORDER BY bID DESC LIMIT 1); -- Schritt 1: Kindtabellen löschen (alle, die bID als FK enthalten) DELETE FROM Position WHERE bID = @bestellung; DELETE FROM Bestellung_Lager WHERE bID = @bestellung; DELETE FROM Mitarbeiter_Bestellung WHERE bID = @bestellung; -- Schritt 2: Elterntabelle löschen DELETE FROM Bestellung WHERE bID = @bestellung;
Vorgehen bei referentiellem Löschen:
1. Im Relationen-Modell alle Tabellen finden, die den PK der zu löschenden Tabelle als FK (#) eingetragen haben.
2. Diese Kindtabellen zuerst löschen (ggf. auch deren Kindtabellen).
3. Erst dann die Elterntabelle löschen.
4. Wenn eine Spalte nur auf NULL gesetzt werden soll statt gelöscht: zuerst UPDATE … SET … = NULL, dann DELETE.

4.3 DELETE mit Unterabfrage (MySQL-Sonderregel)

Erkennungsmerkmal: „die fünf am wenigsten verkauften … löschen" — Auswahl per Aggregat
MySQL erlaubt es nicht, dieselbe Tabelle in einem DELETE … WHERE id IN (SELECT … FROM gleicheTabelle) direkt zu verwenden. Workaround: Unterabfrage in eine weitere Unterabfrage einwickeln (Alias-Trick).
DELETE mit verschachtelter Unterabfrage — MySQL-Workaround (ABI 2025 B)
DELETE FROM Getraenk WHERE gid IN ( SELECT gid FROM ( SELECT gid, SUM(anzahlGetraenke) FROM Kauf GROUP BY gid ORDER BY SUM(anzahlGetraenke) ASC LIMIT 5 ) AS x );

5 · SELECT — Grundabfragen & Filterung

Einfache Abfragen aus einer oder wenigen Tabellen mit WHERE-Bedingungen.

5.1 Textsuche mit LIKE

Erkennungsmerkmal: „enthält", „beginnt mit", „aus dem Bereich", Datumsfilterung nach Monat
% = beliebig viele Zeichen (auch null). _ = genau ein Zeichen (selten verwendet im Abitur).
-- Enthält 'Drucker' irgendwo im Feld WHERE beschreibung LIKE '%Drucker%' -- PLZ beginnt mit 6 (PLZ-Bereich) WHERE plz LIKE '6%' -- Datum im Januar 2020 (Datumsformat YYYY-MM-DD) WHERE datum LIKE '2020-01-%' -- Alternativ mit BETWEEN für Datumsbereiche WHERE datum BETWEEN '2020-01-01' AND '2020-01-31'

5.2 IS NULL — fehlende / noch nicht gesetzte Werte

Erkennungsmerkmal: „noch nicht geliefert", „noch nicht besetzt", „nicht zugeordnet"
Felder, die noch keinen Wert haben, sind in SQL NULL. Vergleich mit = NULL funktioniert nicht — immer IS NULL oder IS NOT NULL verwenden.
-- Kartons, die noch nicht eingelagert sind (kein Segment zugeordnet) WHERE segmentnr IS NULL -- Bestellungen, die noch nicht geliefert wurden WHERE lieferDatum IS NULL -- Stellen, die noch nicht besetzt sind (mid noch nicht vergeben) WHERE mid IS NULL

5.3 DISTINCT — Mehrfachnennungen vermeiden

Erkennungsmerkmal: „Mehrfachnennung ist zu unterbinden", „soll jeder nur einmal erscheinen"
Entsteht häufig bei Joins über n:m-Beziehungen, wo ein Datensatz durch mehrere Verbindungen mehrfach erscheint.
SELECT DISTINCT name, vorname FROM Mitglied, Buchung, Fahrzeug WHERE Mitglied.mitgliedsnr = Buchung.mitgliedsnr AND Buchung.kennzeichen = Fahrzeug.kennzeichen AND hersteller = 'Mercedes' ORDER BY name, vorname;

6 · SELECT über mehrere Tabellen — JOIN

Wenn die Ausgabe Spalten aus mehr als einer Tabelle enthält, müssen die Tabellen verknüpft werden. Beide Schreibweisen sind im Abitur akzeptiert.
Alte Syntax (impliziter Join)
SELECT ... FROM Tabelle1, Tabelle2 WHERE Tabelle1.key = Tabelle2.key AND ... weitere Bedingungen
JOIN-Syntax (explizit)
SELECT ... FROM Tabelle1 JOIN Tabelle2 ON T1.key = T2.key WHERE ... weitere Bedingungen
USING-Kurzschreibweise: Wenn der verknüpfte Spaltenname in beiden Tabellen identisch ist (z.B. filialnr in beiden), kann JOIN Tabelle USING(filialnr) statt ON t1.filialnr = t2.filialnr verwendet werden. Beide sind gleichwertig.

6.1 Mehrere Tabellen verknüpfen — Strategie

Wie viele Tabellen brauche ich? — FK-Kette im Relationen-Modell verfolgen
Ausgangspunkt: Welche Tabelle enthält die gewünschten Ausgabespalten? Welche weiteren Tabellen liefern die restlichen Spalten? Den Weg über die FK-Verbindungen (#-Markierung) im Relationen-Modell entlanggehen und jeden Zwischenschritt als JOIN hinzufügen.

Beispiel: Kundenname + Fluginfo → Kunde → Ticket → Flug = 3 JOINs nötig.
3-Tabellen-JOIN (ABI 2021 A, ABI 2024 B)
-- Kennzeichen + Fahrerdaten für eine Bestellnummer ermitteln SELECT kennzeichen, vorname, nachname FROM Fahrzeug INNER JOIN Lieferauftrag USING (fahrzeugnr) INNER JOIN Fahrer USING (fahrernr) WHERE bestellnr = 4711;

6.2 Tabellenaliase

Kürzere Schreibweise bei vielen Tabellen — immer nützlich
Aliase mit AS (oder direkt ohne AS) nach dem Tabellennamen vergeben, dann mit dem Kürzel referenzieren. Wichtig bei gleichnamigen Spalten in mehreren Tabellen.
SELECT l.persNr, l.name, l.vorname, COUNT(*) AS Stundenzahl FROM unterrichtsstunde u, lehrer l WHERE l.persNr = u.persNr AND klSchuljahr = '2014/15' GROUP BY l.persNr, l.name, l.vorname;

7 · LEFT JOIN — Alle … auch die ohne Treffer

Eines der wichtigsten Muster im Abitur. Sofort erkennen lernen!
Sofort-Erkenner: Wenn die Aufgabe explizit fordert, dass Datensätze auch dann ausgegeben werden sollen, wenn auf der anderen Seite nichts vorhanden ist — das ist LEFT JOIN. Typische Formulierungen:
— „Alle Fahrer sollen erscheinen, auch solche, die noch keinen Lieferauftrag hatten"
— „Auch Rechnungen, für die noch keine Zahlungen vorliegen, sollen berücksichtigt werden"
— „Es sollen auch alle Lager ausgegeben werden, welche noch keine Bestellung aufgegeben haben"
— „Alle Kunden ausgeben, auch die, die nur ein Probetraining absolvieren und nicht durch einen Vertrag gebunden sind"

7.1 Grundmuster LEFT JOIN

Die „volle" Tabelle steht links — die optionale rechts
FROM VolleTabelle LEFT JOIN OptionaleTabelle ON/USING (…)
Alle Zeilen aus der linken Tabelle erscheinen im Ergebnis. Zeilen, für die in der rechten Tabelle kein Treffer existiert, erhalten dort NULL-Werte.

COUNT mit LEFT JOIN: COUNT(rechteTabelle.spalte) zählt nur echte Treffer (NULL wird nicht gezählt). COUNT(*) würde auch die NULL-Zeilen zählen — das ist fast immer falsch!
LEFT JOIN — Fahrer auch ohne Lieferauftrag (ABI 2021 A)
-- Alle Fahrer inkl. Anzahl ihrer Aufträge (0 wenn noch keine) SELECT vorname, nachname, COUNT(bestellnr) AS Anzahl -- ↑ COUNT auf die rechte Tabellenspalte! FROM Fahrer LEFT JOIN Lieferauftrag USING (fahrernr) GROUP BY fahrernr ORDER BY Anzahl DESC;
LEFT JOIN — Rechnungen auch ohne Zahlungen (ABI 2019 B)
-- Rechnungen mit Summe der Zahlungen — auch unbezahlte Rechnungen SELECT r.rechnr, r.betragRechnung, SUM(betrag) AS gezahlt FROM rechnung r LEFT JOIN zahlung z ON r.rechnr = z.rechnr WHERE r.knr = 1073 GROUP BY r.rechnr;
LEFT JOIN — Nutzer auch ohne Beiträge (ABI 2023 A)
-- Alle Nutzer, auch solche ohne Beiträge (NULL in Beitragsspalten) SELECT benutzerName AS Benutzername, titel AS Beitragstitel, erstelltAm AS Erstellungsdatum FROM Nutzer N LEFT JOIN Beitrag B ON N.benutzerName = B.autor
HAVING mit IS NULL — unbezahlte Rechnungen herausfiltern
Bei einem LEFT JOIN kann SUM(betrag) den Wert NULL ergeben, wenn gar keine Zahlungen vorliegen. Um diese Fälle mitzunehmen:
HAVING (bishergezahlt < r.betragRechnung OR bishergezahlt IS NULL)

8 · WHERE NOT IN — Datensätze ohne Verbindung

Wenn Datensätze gesucht werden, die zu keinem Eintrag in einer anderen Tabelle passen.
Sofort-Erkenner: Das Wort „noch nie", „kein/keine", „nicht" in Verbindung mit einer anderen Tabelle — das ist WHERE id NOT IN (SELECT id FROM ...). Beispiele:
— „alle Kunden, die noch nie Tickets reserviert haben"
— „alle Taxis, die noch keinen Einsatz am 30.05.2023 haben"
— „Bilder, die nicht in Beiträgen verwendet werden"
Unterschied NOT IN vs. LEFT JOIN — beide sind im Abitur gleichwertig
Musterlösungen nennen oft: „Lösungen mit LEFT JOIN sind gleichwertig." Welche du verwendest, ist egal — NOT IN ist intuitiver lesbar, LEFT JOIN ... WHERE IS NULL ist performanter (für das Abitur irrelevant).
NOT IN — Kunden ohne Rechnung (ABI 2019 B)
-- Alle Kunden, die noch nie eine Rechnung erhalten haben SELECT * FROM Kunde WHERE knr NOT IN (SELECT knr FROM rechnung);
NOT IN mit Datum-Filter — Taxis ohne Einsatz an einem Tag (ABI 2023 B)
-- Alle Taxis, die am 30.05.2023 keinen Einsatz haben SELECT * FROM Taxi WHERE wagenNr NOT IN (SELECT wagenNr FROM Einsatz WHERE beginn LIKE '2023-05-30%' OR ende LIKE '2023-05-30%');
NOT IN korreliert — Unterricht ohne Lehrbefähigung (ABI 2016 B)
-- Einsätze, bei denen Lehrer Fächer unterrichten, für die sie keine Befähigung haben -- Korrelierte Unterabfrage: u.persNr wird im inneren SELECT genutzt SELECT u.* FROM unterrichtsstunde u WHERE fachkuerzel NOT IN (SELECT fachkuerzel FROM darfunterrichten d WHERE u.persNr = d.persNr) ← korreliert! AND klSchuljahr = '2014/15';
Korrelierte Unterabfrage: Die innere Unterabfrage referenziert eine Spalte der äußeren Abfrage (u.persNr). Sie wird für jede Zeile der äußeren Abfrage neu ausgeführt. Erkennbar daran, dass der Ausschluss personen-spezifisch ist (nicht jeder Lehrer darf die gleichen Fächer).

9 · Aggregatfunktionen & GROUP BY / HAVING

Tritt auf wenn Mengen, Summen, Durchschnitte oder ähnliche Berechnungen über mehrere Zeilen nötig sind.

9.1 Aggregatfunktionen im Überblick

FunktionAufgabentext-SignaleBeispiel
COUNT(*)„Anzahl", „wie viele"COUNT(*) AS Anzahl
COUNT(spalte)„Anzahl" + LEFT JOIN (zählt nur Non-NULL)COUNT(bestellnr) AS Anzahl
SUM(ausdruck)„Summe", „Gesamtbetrag", „Gesamtgewicht", „Umsatz"SUM(preis * anzahl) AS Umsatz
AVG(spalte)„Durchschnitt", „über dem Durchschnittlichen"AVG(verbrauch_vorjahr)
MAX(spalte)„höchste", „neueste", „letzter"MAX(bID) → letzte Bestellung
MIN(spalte)„niedrigste", „günstigste"MIN(preis)

9.2 GROUP BY — Regel: alle nicht-aggregierten SELECT-Spalten

Faustregel: Alles im SELECT, was keine Aggregatfunktion ist → muss ins GROUP BY
Ausnahme: Spalten, die funktional vom Primärschlüssel abhängen (z.B. GROUP BY persNr reicht dann aus, auch wenn name, vorname im SELECT stehen — aber im Abitur werden sie trotzdem mitgenannt, um sicher zu gehen).
SELECT l.persNr, l.name, l.vorname, COUNT(*) AS Stundenzahl FROM unterrichtsstunde u, lehrer l WHERE l.persNr = u.persNr AND klSchuljahr = '2014/15' GROUP BY l.persNr, l.name, l.vorname; -- ↑ alle drei nicht-aggregierten Spalten aus dem SELECT

9.3 HAVING — Filter auf Aggregatwerte

WHERE filtert Zeilen vor dem Gruppieren — HAVING filtert Gruppen nach dem Aggregieren
HAVING verwenden wenn die Bedingung auf einem Aggregatwert (COUNT, SUM, …) basiert.
Merkhilfe: Wenn du WHERE COUNT(...) oder WHERE SUM(...) schreiben würdest → es muss HAVING sein.
GROUP BY + HAVING (ABI 2017 B, ABI 2022 B, ABI 2025 B)
-- Kunden, die mindestens 4× ein Mittelklasse-Fahrzeug gebucht haben SELECT name, vorname, COUNT(*) AS Anzahl FROM Mitglied, Buchung, Fahrzeug WHERE Mitglied.mitgliedsnr = Buchung.mitgliedsnr AND Buchung.kennzeichen = Fahrzeug.kennzeichen AND Fahrzeug.klasse = 'Mittel' GROUP BY name, vorname HAVING Anzahl >= 4; -- Umsatz je Getränkestand (ABI 2025 B) SELECT Getraenkestand.standort, SUM(Getraenk.preis * Kauf.anzahlGetraenke) AS Umsatz FROM Kauf JOIN Getraenkestand USING(gsid) JOIN Getraenk USING(gid) GROUP BY Getraenkestand.standort;

10 · ORDER BY & LIMIT — Sortierung und Begrenzung

Fast immer kombiniert. LIMIT taucht häufig bei Top-N-Abfragen auf.
AufgabentextSQL-KonstruktBeispiel
„aufsteigend sortiert", „alphabetisch", „nach … sortiert" (ohne Zusatz) ORDER BY spalte ASC ORDER BY name ASC
„absteigend sortiert", „die höchsten zuerst" ORDER BY spalte DESC ORDER BY Verbrauch DESC
„die drei / fünf / zehn … mit dem höchsten/letzten" ORDER BY … DESC LIMIT N ORDER BY Gesamtmenge DESC LIMIT 10
„die letzte Bestellung", „der neueste Eintrag" ORDER BY id/datum DESC LIMIT 1 ORDER BY bID DESC LIMIT 1
„die nächsten fünf … chronologisch" WHERE datum >= NOW() ORDER BY datum ASC LIMIT 5 ABI 2024 A

11 · Unterabfragen (Subqueries)

Unterabfragen ermitteln Werte, die in der Hauptabfrage als Vergleichswert oder Filter dienen.

11.1 Vergleich mit Aggregat (AVG / MAX)

Erkennungsmerkmal: „über dem Durchschnitt", „unter dem Mindestbestand"
Wenn eine Filterbedingung auf einem aggregierten Wert basiert, der erst berechnet werden muss.
-- Kunden mit überdurchschnittlichem Verbrauch (ABI 2016 A) SELECT name, vorname, verbrauch_vorjahr FROM Kunde, Vertrag WHERE Kunde.kundennummer = Vertrag.kundennummer AND verbrauch_vorjahr > (SELECT AVG(verbrauch_vorjahr) FROM Vertrag);

11.2 „Beide Bedingungen erfüllen" (Schnittmenge via IN)

Erkennungsmerkmal: „Filme, in denen Schauspieler A und B mitgespielt haben"
Wenn ein Datensatz gleichzeitig zwei verschiedene Bedingungen in einer n:m-Tabelle erfüllen muss (z.B. an zwei Wettbewerben gleichzeitig teilgenommen), löst man das über eine Unterabfrage mit IN.
Schnittmenge — Filme mit zwei bestimmten Schauspielern (ABI 2021 B)
-- Filme, in denen Amy Bale (sid 114) UND Christian Adams (sid 111) mitgespielt haben SELECT F.titel FROM Film F, Besetzung B WHERE F.fid = B.fid AND B.sid = 111 AND F.fid IN (SELECT F.fid FROM Film F, Besetzung B WHERE F.fid = B.fid AND B.sid = 114);

11.3 Unterabfrage im SELECT (skalare Unterabfrage)

Erkennungsmerkmal: Pro Gruppe soll ein separater aggregierter Wert aus einer anderen Tabelle erscheinen
Wenn für jede Zeile des Ergebnisses ein Wert benötigt wird, der aus einer komplett anderen Abfrage stammt — z.B. „Benötigte Dosen" je Impfstoff, wobei die Daten aus einer anderen Tabelle kommen.
Skalare Unterabfrage im SELECT (ABI 2021 C)
-- Vorrätige Dosen aus Standort, benötigte Dosen aus Impfung (andere Tabelle) SELECT bezeichnung AS Impfstoff, SUM(istAnzahlImpfdosen) AS 'Vorrätige Dosen', (SELECT COUNT(*) FROM impfung i WHERE (i.termin2 IS NULL OR i.termin2 > NOW()) AND Standort.bezeichnung = i.bezeichnung GROUP BY i.bezeichnung ) AS 'Benötigte Dosen' FROM Standort GROUP BY bezeichnung;

12 · Datumsfunktionen (MySQL)

Werden fast immer als Hinweis im Aufgabentext eingeführt. Die Syntax ist nie auswendig zu lernen — sie wird gegeben.
FunktionRückgabeEinsatz im AbiturJahr
NOW() aktuelles Datum + Uhrzeit „aktuelles Datum", Einfügen mit heutigem Datum, Vergleich mit Zukünftigem alle Jahre
YEAR(datum) Jahreszahl als Integer „im vergangenen Jahr" → YEAR(datum) = YEAR(NOW())-1, Baujahr eintragen 2017–2025
MONTH(datum) Monatszahl 1–12 „im Monat Januar" → MONTH(datum) = 1 2019 B
datum LIKE 'YYYY-MM-%' boolesch Datumsfilter nach Monat — einfachste und häufigste Methode alle Jahre
TIMEDIFF(t1, t2) TIME-Differenz „Lieferdauer mehr als 45 Minuten" → HOUR(TIMEDIFF(…)) / MINUTE(…) 2021 A
TIMESTAMPDIFF(MINUTE, t1, t2) Minuten als Integer „Anzahl Stunden" → TIMESTAMPDIFF(MINUTE,…)/60 2023 B
datum BETWEEN d1 AND d2 boolesch Zeitraum-Filter, z.B. „1. Quartal 2025" → BETWEEN '2025-01-01' AND '2025-03-31' 2022–2025
IF(bedingung, wert1, wert2) wert1 oder wert2 „gibt 'Ja' aus falls volljährig, sonst 'Nein'" 2025 B
INTERVAL N YEAR/MONTH/DAY Datumsintervall Volljährigkeitscheck: gebDatum <= NOW() - INTERVAL 18 YEAR 2025 B
CONCAT(arg1, arg2) verknüpfter String „Arbeitszeit von – bis" als Spalte: CONCAT(beginn,' - ',ende) 2023 B
DATEADD(interval, n, datum) neues Datum „ein Jahr ab jetzt": beginn <= DATEADD(year,1,NOW()) 2024 A
ROUND(x, n), POWER(m,n) gerundeter Wert, Potenz Zinsberechnung (komplexe Formel direkt in SET): werden stets im Hinweis erklärt 2022 B
Hinweis-Prinzip: Alle nötigen Funktionen werden im Aufgabentext explizit als Hinweis mit Syntax erklärt. Du musst die Syntax nicht auswendig kennen — du musst nur verstehen, wann eine Funktion einzusetzen ist und die angegebene Syntax korrekt nutzen.

13 · CREATE TABLE & ALTER TABLE

Tritt selten auf (bisher nur ABI 2021 A), aber wenn, dann mit vollem Umfang: Tabelle erstellen, Spalte hinzufügen, Fremdschlüssel setzen, Daten einfügen.
Erkennungsmerkmal: Die Aufgabe beschreibt eine komplett neue Tabelle mit Attributen, die in die Datenbank aufgenommen werden soll. Dazu wird oft auch gefordert, eine bestehende Tabelle um einen Fremdschlüssel zu ergänzen (ALTER TABLE).
CREATE TABLE + ALTER TABLE + INSERT mit Unterabfrage (ABI 2021 A)
-- 1. Neue Tabelle anlegen CREATE TABLE Geschaeftsfuehrer ( personalnr INTEGER AUTO_INCREMENT, vorname VARCHAR(64), nachname VARCHAR(64), PRIMARY KEY (personalnr) ); -- 2. Bestehende Tabelle um FK-Spalte erweitern ALTER TABLE Filiale ADD gf_personalnr INTEGER; ALTER TABLE Filiale ADD FOREIGN KEY (gf_personalnr) REFERENCES Geschaeftsfuehrer(personalnr); -- 3. Neue Person einfügen (AUTO_INCREMENT → ID weglassen) INSERT INTO Geschaeftsfuehrer (vorname, nachname) VALUES ('Mira', 'Bellenbaum'); -- 4. Filiale einfügen — FK-Wert per Unterabfrage ermitteln INSERT INTO Filiale (filialnr, strassehausnr, plz, ort, gf_personalnr) VALUES (3, 'Bahnhofstr. 3', '37213', 'Witzenhausen', (SELECT personalnr FROM Geschaeftsfuehrer WHERE vorname = 'Mira' AND nachname = 'Bellenbaum'));
Reihenfolge bei CREATE + INSERT
1. Neue Tabelle erstellen (CREATE TABLE)
2. Bestehende Tabelle erweitern (ALTER TABLE ADD)
3. FK-Constraint hinzufügen (ALTER TABLE ADD FOREIGN KEY)
4. Datensatz in neue Tabelle einfügen (INSERT)
5. Datensatz in erweiterte Tabelle einfügen (INSERT mit Unterabfrage für den neuen FK-Wert)

14 · SET @Variable (MySQL-spezifisch)

Wird als expliziter Hinweis im Aufgabentext eingeführt. Dient dazu, einen Wert einmalig zu ermitteln und in mehreren Folgebefehlen wiederzuverwenden.
Erkennungsmerkmal: Hinweis auf SET @variablenName = (SELECT … FROM …) im Aufgabentext
Wenn ein Wert (z.B. die ID der letzten Bestellung) erst ermittelt und dann in mehreren DELETE- oder UPDATE-Statements genutzt werden soll. Ohne Variable müsste man dieselbe Unterabfrage mehrfach wiederholen.
-- Wert einmalig ermitteln und in Variable speichern SET @bestellung = ( SELECT bID FROM Bestellung ORDER BY bID DESC LIMIT 1 ); -- Variable in mehreren Folgebefehlen verwenden DELETE FROM Position WHERE bID = @bestellung; DELETE FROM Bestellung_Lager WHERE bID = @bestellung; DELETE FROM Bestellung WHERE bID = @bestellung;
Hinweis der Musterlösung (ABI 2025 A): „Eine Umsetzung ohne SET ist als gleichwertig anzusehen." — Wenn du die Variable durch eine wiederholte Unterabfrage ersetzt, wird das genauso gewertet. Die Variable macht den Code nur lesbarer.

15 · SQL-Anweisung erläutern (Sonderaufgabe)

Tritt selten auf (ABI 2017 B). Eine vorgegebene SQL-Anweisung soll in eigenen Worten erklärt werden.
Vorgehen: Struktur beschreiben → Verbindungen erklären → Ergebnis formulieren
1. Struktur: Aus wie vielen Tabellen werden Daten abgefragt? Wie werden sie verbunden (INNER JOIN, Bedingung)?
2. Filter: Was macht die WHERE-Klausel? (z.B. IN-Liste beschreiben)
3. Ergebnis: Welche Spalten werden ausgegeben und was bedeuten sie inhaltlich?
Beispiel (ABI 2017 B): „Es werden Daten aus drei verbundenen Tabellen abgefragt. Durch INNER JOIN werden jeweils die Datensätze verknüpft, für die die in der ON-Bedingung angegebene Gleichheit gilt. Der IN-Operator in der WHERE-Klausel filtert auf Mitglieder mit bestimmten Nummern. Das Ergebnis enthält alle Buchungen dieser Mitglieder mit Buchungsnummer, Name, Vorname und Kennzeichen."
Kartesisches Produkt — häufiger Erläuterungs-Fallstrick (ABI 2023 A)
Wenn zwei Tabellen FROM Tabelle1, Tabelle2 ohne Verknüpfungsbedingung kombiniert werden, entsteht das kartesische Produkt (jede Zeile aus T1 × jede Zeile aus T2). Das ist fast immer falsch und muss durch einen JOIN oder eine WHERE-Bedingung ersetzt werden.

16 · Schnell-Referenz: Schlüsselwörter → SQL-Muster

Erkenne am Aufgabentext sofort, welches Muster gefragt ist.
Schlüsselwort / Phrase im Aufgabentext → SQL-Muster / Sektion
neu", „wird aufgenommen", „wird hinzugefügt", „wird eingetragen", „erstmalig"INSERT INTO (Sektion 2)
ID wird automatisch vergeben", „AUTO_INCREMENT"→ INSERT ohne PK / mit NULL (Sektion 2.2)
Neuer FK-Wert nur per Name bekannt (ID unbekannt)INSERT … VALUES (…, (SELECT id FROM … WHERE name=…)) (Sektion 2.3)
Neuer Kunde + erste Bestellung gleichzeitig→ mehrstufiges INSERT in FK-Reihenfolge (Sektion 2.4)
„soll aktualisiert werden", „wird übernommen von", „auf … gesetzt"UPDATE … SET (Sektion 3)
„um X% erhöhen/verringern", Bestand anpassenSET preis = preis * 1.X (Sektion 3.2)
Neuer Wert kommt aus einer anderen Tabelle (Person, Objekt per Name)SET id = (SELECT id FROM … WHERE name=…) (Sektion 3.3)
„soll gelöscht werden" — Abhängigkeiten bereits bereinigt→ einfaches DELETE (Sektion 4.1)
referentielle Integrität", „keine kaskadierende Löschung"→ mehrstufiges DELETE, Kindtabellen zuerst (Sektion 4.2)
Löschen der N am wenigsten / meisten X (Aggregat)→ DELETE mit doppelter Unterabfrage-Schachtelung (Sektion 4.3)
enthält", „beginnt mit", Datum nach Monat filternLIKE '%…%', LIKE '2020-01-%' (Sektion 5.1)
„noch nicht geliefert", „noch nicht besetzt", „nicht zugeordnet"WHERE spalte IS NULL (Sektion 5.2)
„Mehrfachnennung unterbinden", „soll nur einmal erscheinen"SELECT DISTINCT (Sektion 5.3)
Ausgabe enthält Spalten aus >1 Tabelle→ JOIN / implizite Verknüpfung (Sektion 6)
auch … die noch keine … haben", „auch ohne Treffer ausgeben"LEFT JOIN (Sektion 7)
noch nie", „keinen … haben", „nicht in … enthalten"WHERE id NOT IN (SELECT …) (Sektion 8)
„Anzahl", „Summe", „je … die Summe", „Umsatz"COUNT/SUM + GROUP BY (Sektion 9)
Filter auf aggregierten Wert: „die mehr als X … haben"HAVING COUNT/SUM > X (Sektion 9.3)
„die drei … mit dem höchsten", „die letzten zehn"ORDER BY … DESC LIMIT N (Sektion 10)
„über dem Durchschnitt", „unter dem Soll-Bestand"WHERE x > (SELECT AVG(x) …) (Sektion 11.1)
„in denen Person A und Person B … mitwirkten"AND fid IN (SELECT fid … WHERE sid=…) (Sektion 11.2)
„im Monat Januar", „im vergangenen Jahr", „aktuelles Datum"LIKE '…%' oder YEAR() = YEAR(NOW())-1 (Sektion 12)
Hinweis: NOW(), TIMEDIFF, INTERVAL, IF(), BETWEEN→ Datumsfunktionen gemäß Hinweis anwenden (Sektion 12)
„Tabelle … soll in der Datenbank ergänzt werden" + AttributbeschreibungCREATE TABLE + ALTER TABLE (Sektion 13)
Hinweis: SET @variablenName = (SELECT … FROM …);→ MySQL-Variable nutzen (Sektion 14)
Erläutern Sie den Aufbau und die inhaltliche Bedeutung"→ Strukturbeschreibung in Text (Sektion 15)
Beschreibt zwei Tabellen ohne WHERE-Verknüpfung → Fehler identifizieren→ kartesisches Produkt, durch LEFT JOIN lösen (Sektion 15)