Zum Inhalt springen
Zurück zur Themenübersicht

Datenmodellierung und Datenbanken

Abfragen: aus Daten Informationen gewinnen

Auswählen, filtern, sortieren, verbinden und zusammenfassen: die fünf Dinge, aus denen jede Datenbankabfrage besteht.

Benötigte Grundlagen

Dieses Vorwissen brauchst du für das Kapitel. Schau kurz nach, wenn dir etwas davon nicht mehr präsent ist, sonst leg direkt los.

Einführung

Die Datenbank ist gebaut, die Tabellen sind gefüllt. Und jetzt?

Eine Datenbank, aus der man nichts herausbekommt, ist nur ein sehr ordentlicher Aktenschrank. Ihren Wert bekommt sie erst durch Abfragen: „Welche Bücher sind gerade ausgeliehen?“, „Wer hat mehr als drei Bücher?“, „Wie viele Ausleihen gab es im März?“

Das Bemerkenswerte daran ist, wie wenig man dafür lernen muss. Fast jede Abfrage besteht aus denselben fünf Bausteinen, und man beschreibt darin nicht, wie gesucht werden soll, sondern nur, was man haben will.

Das kannst du nach diesem Kapitel

  • eine Abfrage aus Auswahl, Filter, Sortierung, Verbindung und Zusammenfassung aufbauen.

  • einfache Abfragen in SQL lesen und selbst formulieren.

  • Bedingungen mit und, oder und nicht verknüpfen.

  • zwei Tabellen über ihren verbinden.

  • erklären, warum eine Abfrage beschreibt statt vorschreibt, und was daraus folgt.

Unsere Beispieldatenbank

Wir arbeiten mit den Tabellen aus dem vorigen Kapitel:

Schueler(schuelerNr, vorname, nachname, klasse)
Buch(buchNr, titel, autor, verlag, jahr)
Ausleihe(ausleihNr, schuelerNr, buchNr, ausleihdatum, rueckgabedatum)

Die Ausgangstabelle

SchuelerschuelerIDnameklasseIDpunkte1Anna11202Ben1453Cem2784Dora1515Eren233

Fünf Zeilen, vier Spalten, klein genug, um jede Abfrage von Hand nachzuprüfen. Genau dafür ist sie da: Wer ein Abfrageergebnis glaubt, statt es nachzuzählen, merkt einen Denkfehler erst bei einer Tabelle, die zu groß zum Nachzählen ist.

Baustein 1: Auswahl

Zuerst sagt man, welche Spalten man sehen will und aus welcher Tabelle.

SELECT titel, autor
FROM Buch;

Gelesen: „Wähle Titel und Autor aus der Tabelle Buch.“ Das Ergebnis ist wieder eine Tabelle, nur mit weniger Spalten.

Ein Stern steht für alle Spalten:

SELECT * FROM Buch;

Baustein 2: Filter

Meistens will man nicht alle Zeilen. Die Bedingung steht hinter dem Wort WHERE:

SELECT titel, jahr
FROM Buch
WHERE jahr > 2000;

Die Bedingung wird für jede Zeile einzeln geprüft. Trifft sie zu, kommt die Zeile ins Ergebnis, sonst nicht.

Zur Verfügung stehen die Vergleiche ==, ≠\neq, <<, >>, ≤\le, ≥\ge sowie die Textsuche mit LIKE, bei der ein Prozentzeichen für beliebig viele Zeichen steht:

WHERE nachname LIKE 'Web%'

Mehrere Bedingungen verknüpft man mit AND, OR und NOT:

WHERE jahr > 2000 AND verlag = 'Dressler'

🔴 Beachte den Unterschied zwischen AND und OR genau. „Bücher von Kästner und von Ende“ heißt umgangssprachlich, dass man beide haben will, in der Abfrage aber:

WHERE autor = 'Kästner' OR autor = 'Ende'

Mit AND käme kein einziges Buch heraus, denn kein Buch hat gleichzeitig zwei verschiedene Autoren. Die Bedingung wird je Zeile geprüft, nicht über die Menge hinweg. Das ist eine der häufigsten Fehlerquellen überhaupt.

Filter und Projektion an einem Bild

SchuelerschuelerIDnameklasseIDpunkte1Anna11202Ben1453Cem2784Dora1515Eren233Filter: punkte > 50. Das sind Anna,Cem und Dora. Projektion: nur nameund punkte.

Zwei verschiedene Dinge, absichtlich verschieden markiert. Der Filter streicht Zeilen: getönt sind genau die drei mit mehr als 5050 Punkten, 120120, 7878 und 5151; Ben mit 4545 und Eren mit 3333 fallen heraus. Die Projektion streicht Spalten: farbig sind die Köpfe von name und punkte. Übrig bleibt, wo beides zutrifft, drei Zeilen mit je zwei Spalten. Und die Reihenfolge ist egal: Erst filtern und dann Spalten wegnehmen ergibt dasselbe wie umgekehrt.

Baustein 3: Sortierung

Weil die Zeilenreihenfolge einer Tabelle nichts bedeutet, muss man sie ausdrücklich anfordern:

SELECT titel, jahr
FROM Buch
ORDER BY jahr DESC;

ASC sortiert aufsteigend (der Standard), DESC absteigend.

Baustein 4: Tabellen verbinden

Jetzt kommt der Schritt, der Datenbanken erst mächtig macht. Die Ausleihtabelle enthält nur Nummern. Wer wissen will, welcher Schüler welches Buch hat, muss drei Tabellen zusammenführen.

Verbunden wird über die Stelle, an der und Primärschlüssel denselben Wert tragen:

SELECT Schueler.nachname, Buch.titel, Ausleihe.ausleihdatum
FROM Ausleihe
JOIN Schueler ON Ausleihe.schuelerNr = Schueler.schuelerNr
JOIN Buch     ON Ausleihe.buchNr     = Buch.buchNr;

Gelesen: „Nimm jede Ausleihe. Suche den Schüler, dessen Nummer dort steht, und das Buch, dessen Nummer dort steht. Zeige Nachname, Titel und Datum.“

Hier zahlt sich die Trennung aus dem Modellierungskapitel aus: Weil der Name einmal gespeichert ist, ist er überall gleich, und die Verbindung stellt ihn bei jeder Ausleihe zur Verfügung. Man speichert einmal und liest beliebig oft zusammen.

Zwei Tabellen verbinden

KlasseklasseIDname110a210bErgebnis des VerbundsnamepunkteklasseAnna12010aBen4510aCem7810bDora5110aEren3310bVerbunden über Schueler.klasseID =Klasse.klasseID. Aus zwei Tabellenwird eine.

Der Verbund ersetzt jeden durch das, worauf er zeigt. Prüfe eine Zeile nach: Anna hatte klasseID 11, und die 11 steht oben bei der 10a, also erscheint unten „10a“. Nichts geht dabei verloren und nichts kommt hinzu: Aus fünf Schülerzeilen werden genau fünf Ergebniszeilen. Erst dadurch wird die Zerlegung aus 10.2 wieder bequem lesbar, man speichert getrennt und liest zusammengesetzt.

Baustein 5: Zusammenfassen

Oft will man keine Liste, sondern eine Zahl. Dafür gibt es Funktionen, die über viele Zeilen hinweg rechnen:

FunktionBedeutung
COUNT(*)Anzahl der Zeilen
SUM(spalte)Summe
AVG(spalte)Mittelwert
MIN, MAXkleinster, größter Wert
SELECT COUNT(*)
FROM Ausleihe
WHERE ausleihdatum >= '2026-03-01';

Will man je Gruppe zusammenfassen, etwa je Schüler, kommt GROUP BY dazu:

SELECT schuelerNr, COUNT(*)
FROM Ausleihe
GROUP BY schuelerNr;

Das Ergebnis hat eine Zeile je Schülernummer und daneben die Anzahl seiner Ausleihen. Man kann sich das als Sortieren nach Schülernummer und anschließendes Zusammenzählen jeder Gruppe vorstellen.

Beschreiben statt vorschreiben

Und jetzt der Gedanke, der über SQL hinausreicht.

In den Algorithmus-Kapiteln hast du Handlungsanweisungen geschrieben: nimm die erste Zahl, vergleiche, gehe zur nächsten. Eine Abfrage tut das gerade nicht. Sie beschreibt nur die Eigenschaften des gewünschten Ergebnisses, und wie es gefunden wird, überlässt sie dem System.

Das hat zwei praktische Folgen:

Erstens kann das System den Weg selbst optimieren. Bei einer Million Bücher wählt es einen ganz anderen Weg als bei zehn, ohne dass die Abfrage sich ändert.

Zweitens bleibt dieselbe Abfrage bei wachsendem Bestand gültig. Ein selbstgeschriebener Suchalgorithmus müsste bei einer Million Zeilen neu durchdacht werden.

Man nennt diese Art zu arbeiten deklarativ („beschreibend“) im Unterschied zum imperativen Programmieren („befehlend“), das du beim kennengelernt hast. Beide haben ihren Platz; sie beantworten verschiedene Arten von Fragen.

Die Reihenfolge im Kopf

Beim Schreiben hilft es, die Bausteine immer in derselben Ordnung durchzugehen:

  1. Woher? (FROM, JOIN) Welche Tabellen brauche ich?
  2. Welche Zeilen? (WHERE) Welche Bedingung müssen sie erfüllen?
  3. Gruppieren? (GROUP BY) Will ich je Gruppe eine Zahl?
  4. Was zeigen? (SELECT) Welche Spalten sollen im Ergebnis stehen?
  5. In welcher Ordnung? (ORDER BY)

Aufgeschrieben wird zwar mit SELECT zuerst, gedacht wird aber von der Tabelle her. Wer sich an diese Reihenfolge hält, vergisst seltener ein JOIN.

Die Reihenfolge im Kopf

SchrittWaspassiertZeilendanach1. TabellenholenSchuelermit Klasseverbinden52. Filternnur punkte> 50behalten33.Zusammenfassenje Klasseeine Zeilebilden24. SpaltenwählenKlassennameund Anzahlausgeben25. Sortierennach Anzahlabsteigend2Aufgeschrieben wird SELECT zuerst,ausgeführt wird es als vorletzterSchritt.

Die rechte Spalte ist der Grund, warum diese Reihenfolge wichtig ist: Bei jedem Schritt bleiben weniger Zeilen übrig, und jeder Schritt arbeitet auf dem Ergebnis des vorigen. Wer zuerst zusammenfasst und dann filtert, filtert bereits verdichtete Zeilen und bekommt etwas anderes heraus. Dass man SELECT ganz vorne hinschreibt, obwohl es fast zuletzt ausgeführt wird, ist eine Eigenheit der Schreibweise, nicht der Verarbeitung.

Von der Frage zur Abfrage

„Welche Bücher des Verlags Dressler sind nach 2000 erschienen? Zeige Titel und Jahr, das neueste zuerst.“

  1. 1

    Woher? Alle Angaben stehen in der Tabelle Buch. Also FROM Buch, kein JOIN nötig.

  2. 2

    Welche Zeilen? Zwei Bedingungen müssen gleichzeitig gelten, also AND: verlag = 'Dressler' AND jahr > 2000.

  3. 3

    Gruppieren? Nein, es ist eine Liste gefragt und keine Zahl.

  4. 4

    Was zeigen? Titel und Jahr.

  5. 5

    In welcher Ordnung? Neuestes zuerst, also absteigend nach Jahr.

    SELECT titel, jahr
    FROM Buch
    WHERE verlag = 'Dressler' AND jahr > 2000
    ORDER BY jahr DESC;
    

Hier ist AND richtig, weil eine Zeile beide Bedingungen erfüllen muss und das möglich ist.

Verbinden und zählen

„Wie viele Bücher hat jeder Schüler ausgeliehen? Zeige Nachname und Anzahl, die Vielleser zuerst.“

  1. 1

    Woher? Die Anzahl steckt in der Ausleihtabelle, der Nachname in der Schülertabelle. Also beide, verbunden über schuelerNr.

  2. 2

    Welche Zeilen? Alle, es gibt keine Einschränkung.

  3. 3

    Gruppieren? Ja, „jeder Schüler“ heißt: je Schüler eine Zeile. Also GROUP BY über den Schüler.

  4. 4

    Was zeigen und wie ordnen? Nachname und die Anzahl, absteigend.

    SELECT Schueler.nachname, COUNT(*) AS anzahl
    FROM Ausleihe
    JOIN Schueler ON Ausleihe.schuelerNr = Schueler.schuelerNr
    GROUP BY Schueler.schuelerNr, Schueler.nachname
    ORDER BY anzahl DESC;
    
  5. 5

    Gruppiert wird bewusst nach der Nummer und nicht nur nach dem Nachnamen: Zwei Schüler können denselben Nachnamen haben, und die dürfen nicht in einer Zeile zusammenfallen. Genau dafür gibt es den .

Eine Zeile je Schüler mit seiner Ausleihzahl, absteigend sortiert.

Typischer Fehler

Für „Zeige alle Bücher von Kästner und von Ende“ die Bedingung

WHERE autor = ’Ka¨stner’ AND autor = ’Ende’\texttt{WHERE autor = 'Kästner' AND autor = 'Ende'}

Diese Abfrage liefert null Zeilen, und zwar zuverlässig.

Der Grund liegt darin, worauf die Bedingung angewendet wird: auf jede Zeile einzeln. Für ein einzelnes Buch würde geprüft, ob sein Autor gleichzeitig Kästner und Ende ist. In der Spalte autor steht aber genau ein Wert, also kann die Bedingung nie erfüllt sein.

Richtig ist OR:

WHERE autor = ’Ka¨stner’ OR autor = ’Ende’\texttt{WHERE autor = 'Kästner' OR autor = 'Ende'}

Jetzt wird je Zeile geprüft, ob eine der beiden Bedingungen zutrifft, und beide Autorengruppen landen im Ergebnis.

Die Ursache der Verwechslung ist die Alltagssprache: Das „und“ in „Bücher von Kästner und Ende“ verbindet die gewünschte Ergebnismenge, nicht die Bedingungen an eine Zeile. Merke dir die Übersetzung: Wo du im Deutschen zwei Sorten aufzählst, steht in der Abfrage OR. Ein AND ist nur dann richtig, wenn eine einzelne Zeile beide Bedingungen zugleich erfüllen kann, etwa „von Kästner und nach 2000 erschienen“.

Übung 1

leicht

Formuliere die Abfragen zur Tabelle Buch(buchNr, titel, autor, verlag, jahr):

a) alle Titel b) alle Bücher, die vor 1990 erschienen sind c) alle Titel von Kästner, alphabetisch sortiert d) die Anzahl aller Bücher

Tipp anzeigen

Zu d): Gefragt ist eine Zahl, keine Liste.

Lösung anzeigen

a) SELECT titel FROM Buch;

b) SELECT * FROM Buch WHERE jahr < 1990;

c) SELECT titel FROM Buch WHERE autor = 'Kästner' ORDER BY titel;

d) SELECT COUNT(*) FROM Buch;

Detaillierte Schritterklärung anzeigen

Hier wird jeder Schritt einzeln erklärt, vor allem, warum er gemacht wird.

Erklärungstiefe

✦ Empfohlen: Standard – Die normale Erklärungstiefe passt zum Einstieg.

  1. 1

    Den Bauplan jeder Abfrage bereitlegen

    Jede Abfrage beantwortet drei Fragen in fester Reihenfolge: Welche Spalten (SELECT), aus welcher Tabelle (FROM), welche Zeilen (WHERE). Dazu kommen bei Bedarf ORDER BY für die Reihenfolge und Funktionen wie COUNT für Zusammenfassungen.

  2. 2

    a) und b): Spalten wählen und Zeilen filtern

    Für alle Titel genügt die Spaltenauswahl ohne Bedingung. Für die Bücher vor 1990 bleiben alle Spalten (der Stern), aber die Zeilen werden über WHERE eingeschränkt.

    SELECT titel FROM Buch;\texttt{SELECT titel FROM Buch;}

  3. 3

    c) Bedingung und Sortierung zusammen

    Gefordert sind Titel (Spalte), nur von Kästner (Bedingung) und alphabetisch (Reihenfolge). Das ergibt alle drei Teile in einer Abfrage: SELECT titel FROM Buch WHERE autor = ’Ka¨stner’ ORDER BY titel;\texttt{SELECT titel FROM Buch WHERE autor = 'Kästner' ORDER BY titel;}

  4. 4

    d) Eine Zahl statt einer Liste

    Gefragt ist die Anzahl, nicht die Bücher selbst. Dafür gibt es eine Zusammenfassungsfunktion: SELECT COUNT(*) FROM Buch;\texttt{SELECT COUNT(*) FROM Buch;} Das Ergebnis ist eine einzige Zeile mit einer einzigen Zahl.

Übung 2

mittel

Nutze die drei Tabellen Schueler, Buch und Ausleihe.

a) Zeige Nachname und Buchtitel aller laufenden Ausleihen (rueckgabedatum ist leer). b) Zeige, wie viele Bücher jede Klasse insgesamt ausgeliehen hat. c) Erkläre, warum in a) zwei JOIN nötig sind. d) Was passiert, wenn man in a) das JOIN auf Buch weglässt?

Tipp anzeigen

„Leer“ heißt in SQL: IS NULL.

Lösung anzeigen

a) Abfrage:

SELECT Schueler.nachname, Buch.titel FROM Ausleihe JOIN Schueler ON Ausleihe.schuelerNr = Schueler.schuelerNr JOIN Buch ON Ausleihe.buchNr = Buch.buchNr WHERE Ausleihe.rueckgabedatum IS NULL;

b) Abfrage:

SELECT Schueler.klasse, COUNT(*) AS anzahl FROM Ausleihe JOIN Schueler ON Ausleihe.schuelerNr = Schueler.schuelerNr GROUP BY Schueler.klasse ORDER BY anzahl DESC;

c) Weil die gewünschten Angaben in drei Tabellen liegen. Die Ausleihtabelle enthält nur Nummern; der Nachname steht in Schueler, der Titel in Buch. Jede Verbindung holt genau eine dieser Angaben dazu, also braucht man zwei.

d) Dann steht die Spalte Buch.titel gar nicht zur Verfügung, und die Abfrage wird mit einer Fehlermeldung abgelehnt. Ersetzt man titel durch buchNr, läuft sie, liefert aber nur Nummern: Man sähe, dass Mara Buch 17 hat, ohne zu erfahren, welches Buch das ist.

Detaillierte Schritterklärung anzeigen

Hier wird jeder Schritt einzeln erklärt, vor allem, warum er gemacht wird.

Erklärungstiefe

✦ Empfohlen: Standard – Die normale Erklärungstiefe passt zum Einstieg.

  1. 1

    Teil a): Woher kommen die Angaben?

    Zuerst wird für jede gewünschte Spalte notiert, in welcher Tabelle sie steht. Diese Liste bestimmt, wie viele Verbindungen nötig sind.

    Zwischenergebnis

    nachname → Schueler · titel → Buch · rueckgabedatum → Ausleihe

    Startpunkt ist immer die Tabelle, die die Fremdschlüssel trägt, hier die Ausleihe. Von dort holt man sich der Reihe nach die Ergänzungen.

  2. 2

    Teil a): Verbindungen aufschreiben

    Jede Verbindung setzt Fremdschlüssel und Primärschlüssel gleich. Es gibt zwei Fremdschlüssel in der Ausleihtabelle, also zwei Verbindungen.

    \text{Ausleihe.schuelerNr} = \text{Schueler.schuelerNr} \qquad \text{Ausleihe.buchNr} = \text{Buch.buchNr}

    Zwischenergebnis

    Zwei JOIN, jeweils mit ihrer Bedingung.

  3. 3

    Teil a): Filter für „laufend“

    Eine Ausleihe ist laufend, wenn noch kein Rückgabedatum eingetragen ist. Ein fehlender Wert heißt in Datenbanken NULL, und darauf prüft man mit IS NULL, nicht mit einem Gleichheitszeichen.

    \texttt{WHERE Ausleihe.rueckgabedatum IS NULL}

    Zwischenergebnis

    Nur die noch nicht zurückgegebenen Bücher bleiben übrig.

  4. 4

    Teil b): Gruppieren statt auflisten

    „Wie viele je Klasse“ verlangt eine Zeile je Klasse. Man verbindet mit der Schülertabelle, weil nur dort die Klasse steht, gruppiert nach ihr und zählt die Zeilen jeder Gruppe.

    \texttt{GROUP BY Schueler.klasse} \quad\text{mit}\quad \texttt{COUNT(*)}

    Zwischenergebnis

    Eine Zeile je Klasse mit der Anzahl ihrer Ausleihen.

    Hier ist die Gruppierung nach dem Klassennamen ausnahmsweise richtig, denn es gibt jede Klassenbezeichnung nur einmal. Bei Personennamen wäre sie falsch.

Übung 3

schwer

a) Formuliere eine Abfrage, die alle Bücher zeigt, die noch nie ausgeliehen wurden. Erkläre die Schwierigkeit. b) Formuliere „Alle Schüler der Klasse 10a, die mehr als zwei Bücher ausgeliehen haben“. c) Ein Mitschüler schreibt WHERE klasse = '10a' OR klasse = '10b' AND jahr > 2000 und wundert sich über das Ergebnis. Erkläre. d) Begründe, warum eine Abfrage bei einer Million Zeilen nicht neu geschrieben werden muss, ein selbstgeschriebener Suchalgorithmus aber möglicherweise schon.

Tipp anzeigen

Zu a): Gesucht ist das Fehlen einer Zeile in einer anderen Tabelle.

Lösung anzeigen

a) Abfrage:

SELECT titel FROM Buch WHERE buchNr NOT IN (SELECT buchNr FROM Ausleihe);

Die Schwierigkeit ist, dass man nach etwas sucht, das nicht da ist. Ein einfaches JOIN verbindet nur, wo Zeilen zueinander passen; ein Buch ohne Ausleihe hat keinen Partner und fiele damit heraus, obwohl es genau das Gesuchte ist. Man muss deshalb erst die Menge aller ausgeliehenen Bücher bestimmen und dann alles nehmen, was nicht darin vorkommt.

b) Abfrage:

SELECT Schueler.nachname, COUNT() AS anzahl FROM Ausleihe JOIN Schueler ON Ausleihe.schuelerNr = Schueler.schuelerNr WHERE Schueler.klasse = '10a' GROUP BY Schueler.schuelerNr, Schueler.nachname HAVING COUNT() > 2;

Die Bedingung an die Klasse steht im WHERE, weil sie einzelne Zeilen betrifft. Die Bedingung an die Anzahl steht im HAVING, weil sie erst nach dem Gruppieren geprüft werden kann; im WHERE gäbe es die Anzahl noch gar nicht.

c) AND bindet stärker als OR. Die Bedingung wird deshalb gelesen als: klasse = '10a' ODER (klasse = '10b' UND jahr > 2000). Aus der 10a kommen also alle, aus der 10b nur die mit jahr > 2000. Gewollt war vermutlich (klasse = '10a' OR klasse = '10b') AND jahr > 2000. Klammern setzen, sobald AND und OR gemischt werden.

d) Weil eine Abfrage nur beschreibt, welches Ergebnis gewünscht ist, und nicht, wie es zu finden ist. Das Datenbanksystem wählt den Weg selbst und kann ihn bei einer Million Zeilen anders wählen als bei zehn, etwa über einen Index. Ein selbstgeschriebener legt den Weg dagegen fest: Wer alle Zeilen der Reihe nach durchsucht, braucht bei einer Million Zeilen hunderttausendmal so lange wie bei zehn, und daran ändert sich nichts, solange der Quelltext gleich bleibt.

Detaillierte Schritterklärung anzeigen

Hier wird jeder Schritt einzeln erklärt, vor allem, warum er gemacht wird.

Erklärungstiefe

✦ Empfohlen: Standard – Die normale Erklärungstiefe passt zum Einstieg.

  1. 1

    a) Nach etwas suchen, das nicht da ist

    Die Schwierigkeit: Gesucht wird das Fehlen einer Zeile. Ein JOIN verbindet nur, wo Zeilen zueinander passen, ein Buch ohne Ausleihe hat keinen Partner und fiele heraus, obwohl es genau das Gesuchte ist. Man bestimmt deshalb erst die Menge aller ausgeliehenen Bücher und nimmt dann alles, was nicht darin vorkommt.

    SELECT titel FROM Buch WHERE buchNr NOT IN (SELECT buchNr FROM Ausleihe);\texttt{SELECT titel FROM Buch WHERE buchNr NOT IN (SELECT buchNr FROM Ausleihe);}

  2. 2

    b) WHERE oder HAVING: Wann existiert die Anzahl?

    Die Bedingung an die Klasse steht im WHERE, weil sie einzelne Zeilen betrifft. Die Bedingung an die Anzahl steht im HAVING, weil sie erst nach dem Gruppieren geprüft werden kann, im WHERE gäbe es die Anzahl noch gar nicht.

    ... WHERE Schueler.klasse = ’10a’ GROUP BY ... HAVING COUNT(*) > 2;\texttt{... WHERE Schueler.klasse = '10a' GROUP BY ... HAVING COUNT(*) > 2;}

  3. 3

    c) AND bindet stärker als OR, deshalb Klammern

    WHERE klasse = ’10a’ OR klasse = ’10b’ AND jahr > 2000\texttt{WHERE klasse = '10a' OR klasse = '10b' AND jahr > 2000} wird gelesen als klasse = ’10a’ OR (klasse = ’10b’ AND jahr > 2000)\texttt{klasse = '10a' OR (klasse = '10b' AND jahr > 2000)}. Aus der 10a kommen also alle, aus der 10b nur die mit jahr > 2000\texttt{jahr > 2000}. Gewollt war vermutlich (klasse = ’10a’ OR klasse = ’10b’) AND jahr > 2000\texttt{(klasse = '10a' OR klasse = '10b') AND jahr > 2000}.

  4. 4

    d) Beschreiben statt vorschreiben: warum SQL mitwächst

    Eine Abfrage beschreibt nur, welches Ergebnis gewünscht ist, nicht, wie es zu finden ist. Das Datenbanksystem wählt den Weg selbst und kann ihn bei einer Million Zeilen anders wählen als bei zehn, etwa über einen Index. Ein selbstgeschriebener Algorithmus legt den Weg dagegen fest.

Zusammenfassung

Abfragen machen aus gespeicherten . Fast jede besteht aus denselben Bausteinen: der Auswahl der Spalten, der Angabe der Quelltabellen, einem Filter über die Zeilen, der Verbindung mehrerer Tabellen über Fremd- und , der Gruppierung mit einer zusammenfassenden Funktion und der Sortierung. Der Filter prüft jede Zeile einzeln; deshalb wird aus dem umgangssprachlichen „und“ bei zwei Sorten ein OR, und deshalb braucht eine Mischung aus AND und OR Klammern. Verbunden wird immer dort, wo Fremdschlüssel und Primärschlüssel denselben Wert tragen, und gruppiert wird nach dem Schlüssel statt nach dem Namen. Der grundsätzliche Unterschied zum Programmieren: Eine Abfrage beschreibt das gewünschte Ergebnis, statt den Weg dorthin vorzuschreiben, und überlässt die Ausführung dem System.