⚠ 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.
Systematische Analyse aller SQL-Datenbankaufgaben aus den Hessischen Abiturprüfungen
(MySQL) 2016–2025. Dieses Dokument zeigt wiederkehrende Muster und Erkennungsmerkmale,
damit du jeden Aufgabentyp sofort erkennen und strukturiert lösen kannst.
⚠ 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 INTOFahrzeugklasseVALUES ("Van", 0.15, 0.25);
-- Nicht alle Spalten bekannt → Spalten explizit nennen (IBAN fehlt)INSERT INTOFahrer (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 weglassenINSERT INTOBestellung (bestellDatum, kNr)
VALUES ('2022-05-02', 7654);
-- Alternativ: NULL als Platzhalterwert für AUTO_INCREMENTINSERT INTOGeschaeftsfuehrer (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 ermittelnINSERT INTOFilm (fid, titel, osprache, fsk, laenge, vid, gid)
VALUES (4723, 'Logo Movie', 'English', 0, 145,
(SELECTvidFROMVerleihWHEREname='Logo Movie Production'),
(SELECTgidFROMGenreWHEREbezeichnung='Animation')
);
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)
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)UPDATEklasseSETpersNr_kl=101702WHEREklBezeichnung='10a'ANDklSchuljahr='2014/15';
-- Produktname ändernUPDATEGetraenkSETbezeichnung='Hessen Cola'WHEREbezeichnung='Fratz Cola';
3.2 UPDATE mit relativer Berechnung (Preis / Bestand)
Der neue Wert ergibt sich aus dem alten Wert durch eine Rechenoperation. Das SET referenziert die Spalte selbst.
-- Preis um 5% erhöhenUPDATEKomponenteSETpreis=preis* 1.05WHEREhersteller='MANU';
-- Preis um 15% erhöhenUPDATEArtikelSETvkpreis=vkpreis* 1.15WHEREtyp='Badetuch';
-- Bestand um 1 verringernUPDATEArtikelSETistBestand=istBestand- 1WHEREartNr=277;
-- Kettenwerte: alter Zählerstand → vorherigen Wert, neuer → konkreten WertUPDATEVertragSETverbrauch_vorjahr= (zaehlerstand_neu-zaehlerstand_alt),
zaehlerstand_alt=zaehlerstand_neu,
zaehlerstand_neu=9999WHEREzaehlernummer=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)
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)UPDATEGirokonto g, Darlehen d
SET g.kontostand= g.kontostand- d.rateWHERE d.referenzkonto= g.ibanAND d.turnus=12AND 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 FROMrechnungWHERErechnr=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 = (SELECTbIDFROMBestellungORDER BYbIDDESC LIMIT1);
-- Schritt 1: Kindtabellen löschen (alle, die bID als FK enthalten)DELETE FROMPositionWHEREbID= @bestellung;DELETE FROMBestellung_LagerWHEREbID= @bestellung;DELETE FROMMitarbeiter_BestellungWHEREbID= @bestellung;-- Schritt 2: Elterntabelle löschenDELETE FROMBestellungWHEREbID= @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 FROMGetraenkWHEREgidIN (
SELECTgidFROM (
SELECTgid, SUM(anzahlGetraenke)
FROMKaufGROUP BYgidORDER BYSUM(anzahlGetraenke) ASCLIMIT5
) 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 FeldWHEREbeschreibungLIKE'%Drucker%'-- PLZ beginnt mit 6 (PLZ-Bereich)WHEREplzLIKE'6%'-- Datum im Januar 2020 (Datumsformat YYYY-MM-DD)WHEREdatumLIKE'2020-01-%'-- Alternativ mit BETWEEN für DatumsbereicheWHEREdatumBETWEEN'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)WHEREsegmentnrIS NULL-- Bestellungen, die noch nicht geliefert wurdenWHERElieferDatumIS NULL-- Stellen, die noch nicht besetzt sind (mid noch nicht vergeben)WHEREmidIS 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.
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 ...
FROMTabelle1, Tabelle2WHERETabelle1.key=Tabelle2.keyAND ... weitere Bedingungen
JOIN-Syntax (explizit)
SELECT ...
FROMTabelle1JOINTabelle2ONT1.key=T2.keyWHERE ... 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.
-- Kennzeichen + Fahrerdaten für eine Bestellnummer ermittelnSELECTkennzeichen, vorname, nachnameFROMFahrzeugINNER JOINLieferauftragUSING (fahrzeugnr)
INNER JOINFahrerUSING (fahrernr)
WHEREbestellnr=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
FROMunterrichtsstunde u, lehrer l
WHERE l.persNr= u.persNrANDklSchuljahr='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)SELECTvorname, nachname, COUNT(bestellnr) AS Anzahl
-- ↑ COUNT auf die rechte Tabellenspalte!FROMFahrerLEFT JOINLieferauftragUSING (fahrernr)GROUP BYfahrernrORDER BY Anzahl DESC;
LEFT JOIN — Rechnungen auch ohne Zahlungen (ABI 2019 B)
-- Rechnungen mit Summe der Zahlungen — auch unbezahlte RechnungenSELECT r.rechnr, r.betragRechnung, SUM(betrag) AS gezahlt
FROMrechnung r
LEFT JOINzahlung z ON r.rechnr= z.rechnrWHERE r.knr=1073GROUP BY r.rechnr;
LEFT JOIN — Nutzer auch ohne Beiträge (ABI 2023 A)
-- Alle Nutzer, auch solche ohne Beiträge (NULL in Beitragsspalten)SELECTbenutzerNameAS Benutzername,
titelAS Beitragstitel,
erstelltAmAS Erstellungsdatum
FROMNutzer N
LEFT JOINBeitrag 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 habenSELECT*FROMKundeWHEREknrNOT IN
(SELECTknrFROMrechnung);
NOT IN mit Datum-Filter — Taxis ohne Einsatz an einem Tag (ABI 2023 B)
-- Alle Taxis, die am 30.05.2023 keinen Einsatz habenSELECT*FROMTaxiWHEREwagenNrNOT IN
(SELECTwagenNrFROMEinsatzWHEREbeginnLIKE'2023-05-30%'ORendeLIKE'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 genutztSELECT u.*FROMunterrichtsstunde u
WHEREfachkuerzelNOT IN
(SELECTfachkuerzelFROMdarfunterrichten d
WHERE u.persNr= d.persNr) ← korreliert!ANDklSchuljahr='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.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
FROMunterrichtsstunde u, lehrer l
WHERE l.persNr= u.persNrANDklSchuljahr='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 habenSELECTname, vorname, COUNT(*) AS Anzahl
FROMMitglied, Buchung, FahrzeugWHEREMitglied.mitgliedsnr=Buchung.mitgliedsnrANDBuchung.kennzeichen=Fahrzeug.kennzeichenANDFahrzeug.klasse='Mittel'GROUP BYname, vornameHAVING Anzahl >=4;-- Umsatz je Getränkestand (ABI 2025 B)SELECTGetraenkestand.standort,
SUM(Getraenk.preis*Kauf.anzahlGetraenke) AS Umsatz
FROMKaufJOINGetraenkestandUSING(gsid)
JOINGetraenkUSING(gid)
GROUP BYGetraenkestand.standort;
10 · ORDER BY & LIMIT — Sortierung und Begrenzung
Fast immer kombiniert. LIMIT taucht häufig bei Top-N-Abfragen auf.
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 habenSELECT F.titelFROMFilm F, Besetzung B
WHERE F.fid= B.fidAND B.sid=111AND F.fidIN
(SELECT F.fidFROMFilm F, Besetzung B
WHERE F.fid= B.fidAND 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)SELECTbezeichnungAS Impfstoff,
SUM(istAnzahlImpfdosen) AS'Vorrätige Dosen',
(SELECTCOUNT(*) FROMimpfung i
WHERE (i.termin2IS NULLOR i.termin2>NOW())
ANDStandort.bezeichnung= i.bezeichnungGROUP BY i.bezeichnung
) AS'Benötigte Dosen'FROMStandortGROUP BYbezeichnung;
12 · Datumsfunktionen (MySQL)
Werden fast immer als Hinweis im Aufgabentext eingeführt. Die Syntax ist nie auswendig zu lernen — sie wird gegeben.
Funktion
Rückgabe
Einsatz im Abitur
Jahr
NOW()
aktuelles Datum + Uhrzeit
„aktuelles Datum", Einfügen mit heutigem Datum, Vergleich mit Zukünftigem
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 anlegenCREATE TABLEGeschaeftsfuehrer (
personalnrINTEGERAUTO_INCREMENT,
vornameVARCHAR(64),
nachnameVARCHAR(64),
PRIMARY KEY (personalnr)
);
-- 2. Bestehende Tabelle um FK-Spalte erweiternALTER TABLEFilialeADDgf_personalnrINTEGER;
ALTER TABLEFilialeADD FOREIGN KEY (gf_personalnr)
REFERENCESGeschaeftsfuehrer(personalnr);
-- 3. Neue Person einfügen (AUTO_INCREMENT → ID weglassen)INSERT INTOGeschaeftsfuehrer (vorname, nachname)
VALUES ('Mira', 'Bellenbaum');
-- 4. Filiale einfügen — FK-Wert per Unterabfrage ermittelnINSERT INTOFiliale (filialnr, strassehausnr, plz, ort, gf_personalnr)
VALUES (3, 'Bahnhofstr. 3', '37213', 'Witzenhausen',
(SELECTpersonalnrFROMGeschaeftsfuehrerWHEREvorname='Mira'ANDnachname='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 speichernSET @bestellung = (
SELECTbIDFROMBestellungORDER BYbIDDESCLIMIT1
);
-- Variable in mehreren Folgebefehlen verwendenDELETE FROMPositionWHEREbID= @bestellung;
DELETE FROMBestellung_LagerWHEREbID= @bestellung;
DELETE FROMBestellungWHEREbID= @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.