Lektion 3.2

SQL und Relationenalgebra

19 min Lesezeit

Die Musikschule hat ihre Daten auf vier Relationen verteilt: Lehrkraft, Kurs, Schueler und Belegung. Nun fragt die Leiterin: Welche Lehrkräfte leiten einen Kurs über 30 Euro Gebühr? Wie viele Schüler hat jeder Kurs, auch einer ohne Schüler? Wer ist in keinem Kurs?

Eine Abfragesprache beschreibt, welche Daten man will, nicht wie das System sie findet. Sie heißt SQL, und hinter ihr steht eine Algebra aus wenigen Operationen auf Relationen. Du lernst beides, dazu Tabellen ändern und den Weg vom Webformular zur Datenbank.

Definition

Abfragen: Projektion, Selektion und Sortierung

Als Beispiel dienen diese Relationen mit ausgedachten Daten.

Lehrkraft

lidnameraum
7Weiss12
8Roth14
9Kern12

Kurs

kidtitelgebuehrlid
10Klavier407
11Gitarre308
12Chor207
13Schlagzeug509

Schueler hat sid und name: 1 Mara, 2 Jonas, 3 Lea, 4 Ben.

Belegung hat die Paare (sid, kid): (1, 10), (1, 11), (2, 10), (3, 10), (3, 12).

Eine Abfrage hat die Form SELECT\texttt{SELECT} Spalten FROM\texttt{FROM} Relation WHERE\texttt{WHERE} Bedingung ORDER BY\texttt{ORDER BY} Spalte. Die Spaltenliste ist die Projektion, die Bedingung die Selektion. Bedingungen vergleichen mit =\texttt{=}, <>\texttt{<>} (ungleich), <\texttt{<}, >=\texttt{>=} und so weiter und lassen sich mit AND\texttt{AND}, OR\texttt{OR}, NOT\texttt{NOT} verbinden. name LIKE ’K%’\texttt{name LIKE 'K\%'} trifft Namen, die mit K beginnen. ORDER BY gebuehr DESC\texttt{ORDER BY gebuehr DESC} sortiert absteigend, ohne DESC\texttt{DESC} aufsteigend. Doppelte Ergebniszeilen entfernt erst SELECT DISTINCT\texttt{SELECT DISTINCT}. So liefert SELECT titel, gebuehr FROM kurs WHERE gebuehr >= 30 ORDER BY gebuehr DESC\texttt{SELECT titel, gebuehr FROM kurs WHERE gebuehr >= 30 ORDER BY gebuehr DESC} die Zeilen Schlagzeug 50, Klavier 40, Gitarre 30.

Definition

Verbund (Join)

Ein Verbund führt Relationen wieder zusammen. kurs JOIN lehrkraft ON kurs.lid = lehrkraft.lid\texttt{kurs JOIN lehrkraft ON kurs.lid = lehrkraft.lid} bildet gedanklich alle Paare aus Kurs und Lehrkraft und behält die, die die Bedingung nach ON\texttt{ON} erfüllen, meist Fremdschlüssel gleich Primärschlüssel. Gleiche Spaltennamen macht man mit dem Relationsnamen eindeutig: kurs.lid\texttt{kurs.lid}. Der einfache Verbund (JOIN\texttt{JOIN}, genauer INNER JOIN\texttt{INNER JOIN}) behält nur Zeilen mit Partner. Der LEFT JOIN\texttt{LEFT JOIN} behält auch Zeilen der linken Relation ohne Partner und füllt die rechten Spalten mit NULL.

Beispiel

Drei Relationen verbinden

Welche Schüler belegen einen Kurs über 30 Euro Gebühr?

ZeileEinrückungAnweisung
10SELECT schueler.name, kurs.titel\texttt{SELECT schueler.name, kurs.titel}
20FROM schueler JOIN belegung ON schueler.sid = belegung.sid\texttt{FROM schueler JOIN belegung ON schueler.sid = belegung.sid}
31JOIN kurs ON belegung.kid = kurs.kid\texttt{JOIN kurs ON belegung.kid = kurs.kid}
40WHERE kurs.gebuehr > 30;\texttt{WHERE kurs.gebuehr > 30;}

Der erste Verbund ordnet jeder Belegung den Schüler zu, der zweite den Kurs. Die Selektion behält Klavier (40) und Schlagzeug (50). Für Schlagzeug gibt es keine Belegung. Ergebnis: Mara, Jonas und Lea, jeweils mit Klavier.

Definition

Aggregatfunktionen und Gruppierung

Aggregatfunktionen fassen Zeilen zu einem Wert zusammen: COUNT\texttt{COUNT}, SUM\texttt{SUM}, AVG\texttt{AVG}, MIN\texttt{MIN}, MAX\texttt{MAX}. GROUP BY\texttt{GROUP BY} bildet Gruppen mit gleichem Wert in den genannten Spalten und liefert je Gruppe eine Zeile. In der Spaltenliste stehen dann neben Aggregaten nur Gruppierungsspalten. WHERE\texttt{WHERE} filtert Zeilen vor der Gruppierung, HAVING\texttt{HAVING} filtert Gruppen danach. Aggregatfunktionen überspringen NULL, nur COUNT(*)\texttt{COUNT(*)} zählt jede Zeile. Die Klauseln stehen in fester Reihenfolge: SELECT, FROM, WHERE, GROUP BY, HAVING, ORDER BY.

Beispiel

Schüler je Kurs zählen

Wie viele Schüler hat jeder Kurs, auch einer ohne Schüler?

ZeileEinrückungAnweisung
10SELECT kurs.titel, COUNT(belegung.sid) AS anzahl\texttt{SELECT kurs.titel, COUNT(belegung.sid) AS anzahl}
20FROM kurs LEFT JOIN belegung ON kurs.kid = belegung.kid\texttt{FROM kurs LEFT JOIN belegung ON kurs.kid = belegung.kid}
30GROUP BY kurs.kid, kurs.titel\texttt{GROUP BY kurs.kid, kurs.titel}
40ORDER BY kurs.kid;\texttt{ORDER BY kurs.kid;}

Der LEFT JOIN\texttt{LEFT JOIN} behält jeden Kurs. Schlagzeug erscheint mit einer Zeile, in der belegung.sid NULL ist. COUNT(belegung.sid)\texttt{COUNT(belegung.sid)} überspringt NULL. Ergebnis: Klavier 3, Gitarre 1, Chor 1, Schlagzeug 0. COUNT(*)\texttt{COUNT(*)} ergäbe für Schlagzeug 1.

Definition

Unterabfragen

Eine Unterabfrage ist eine Abfrage in Klammern innerhalb einer anderen Anweisung. Liefert sie einen Wert, steht sie wie eine Zahl im Vergleich: WHERE gebuehr > (SELECT AVG(gebuehr) FROM kurs)\texttt{WHERE gebuehr > (SELECT AVG(gebuehr) FROM kurs)} wählt Kurse über dem Durchschnitt (40 + 30 + 20 + 50) : 4 = 35, also Klavier und Schlagzeug. Liefert sie eine Spalte, prüfen IN\texttt{IN} und NOT IN\texttt{NOT IN} die Zugehörigkeit: SELECT name FROM schueler WHERE sid NOT IN (SELECT sid FROM belegung)\texttt{SELECT name FROM schueler WHERE sid NOT IN (SELECT sid FROM belegung)} liefert die Schüler ohne Belegung, hier Ben.

Definition

Ändern, DDL, Views und DCL

Daten ändert man mit INSERT\texttt{INSERT}, UPDATE\texttt{UPDATE} und DELETE\texttt{DELETE}, zum Beispiel UPDATE kurs SET gebuehr = 45 WHERE kid = 10\texttt{UPDATE kurs SET gebuehr = 45 WHERE kid = 10}. Ohne WHERE\texttt{WHERE} wirken UPDATE\texttt{UPDATE} und DELETE\texttt{DELETE} auf alle Zeilen. Das DBMS lehnt Änderungen ab, die einen Fremdschlüssel verletzen.

Die DDL (Data Definition Language) legt Strukturen fest: CREATE TABLE\texttt{CREATE TABLE} legt eine Tabelle mit Spalten, PRIMARY KEY\texttt{PRIMARY KEY} und FOREIGN KEY\texttt{FOREIGN KEY} an, ALTER TABLE kurs ADD COLUMN ort TEXT\texttt{ALTER TABLE kurs ADD COLUMN ort TEXT} fügt eine Spalte hinzu, DROP TABLE\texttt{DROP TABLE} entfernt eine Tabelle samt Inhalt.

Ein View ist eine gespeicherte Abfrage mit Namen, die man wie eine Tabelle abfragt: CREATE VIEW kursliste AS SELECT titel, gebuehr FROM kurs\texttt{CREATE VIEW kursliste AS SELECT titel, gebuehr FROM kurs}. Er vereinfacht Abfragen und gibt nur ausgewählte Spalten frei. Die DCL (Data Control Language) vergibt Rechte: GRANT SELECT ON kursliste TO sekretariat\texttt{GRANT SELECT ON kursliste TO sekretariat} erlaubt das Lesen, REVOKE SELECT ON kursliste FROM sekretariat\texttt{REVOKE SELECT ON kursliste FROM sekretariat} nimmt es zurück.

Definition

Relationenalgebra und ihre Abbildung in SQL

Die Relationenalgebra beschreibt Abfragen als verschachtelbare Operationen, die aus Relationen neue machen.

OperationSchreibweiseSQL
Selektionσbedingung(R)\sigma_{\text{bedingung}}(R)WHERE\texttt{WHERE}
ProjektionπA,B(R)\pi_{A, B}(R)SELECT DISTINCT A, B\texttt{SELECT DISTINCT A, B}
KreuzproduktR×SR \times SFROM R, S\texttt{FROM R, S}
VerbundR⋈bedingungSR \bowtie_{\text{bedingung}} SJOIN ... ON\texttt{JOIN ... ON}
VereinigungR∪SR \cup SUNION\texttt{UNION}
DifferenzR∖SR \setminus SEXCEPT\texttt{EXCEPT} (manchmal MINUS\texttt{MINUS})
DurchschnittR∩SR \cap SINTERSECT\texttt{INTERSECT}
UmbenennungρN(R)\rho_{N}(R)AS\texttt{AS}

Vereinigung, Differenz und Durchschnitt verlangen gleiche Attribute. Der Verbund ist ein Kreuzprodukt mit anschließender Selektion. Eine Relation ist eine Menge ohne doppelte Tupel, ein SQL-Ergebnis kann doppelte Zeilen haben. Darum entspricht die Projektion SELECT DISTINCT\texttt{SELECT DISTINCT}.

Beispiel

Von der Algebra zu SQL

Übersetze den Ausdruck in SQL und werte ihn aus.

πname(σgebuehr>30(Kurs⋈Kurs.lid=Lehrkraft.lidLehrkraft))\pi_{\text{name}}\bigl(\sigma_{\text{gebuehr} > 30}(\text{Kurs} \bowtie_{\text{Kurs.lid} = \text{Lehrkraft.lid}} \text{Lehrkraft})\bigr)

Von innen nach außen: Der Verbund wird JOIN ... ON\texttt{JOIN ... ON}, die Selektion WHERE\texttt{WHERE}, die Projektion die Spaltenliste mit DISTINCT\texttt{DISTINCT}.

ZeileEinrückungAnweisung
10SELECT DISTINCT lehrkraft.name\texttt{SELECT DISTINCT lehrkraft.name}
20FROM kurs JOIN lehrkraft ON kurs.lid = lehrkraft.lid\texttt{FROM kurs JOIN lehrkraft ON kurs.lid = lehrkraft.lid}
30WHERE kurs.gebuehr > 30;\texttt{WHERE kurs.gebuehr > 30;}

Die Kurse über 30 Euro sind Klavier (Lehrkraft 7) und Schlagzeug (Lehrkraft 9). Ergebnis: Weiss und Kern.

Definition

Webdatenbank mit Formularen

Eine Webdatenbank besteht aus Browser, Webserver mit einem Programm und DBMS. Ein Formular ist eine Webseite mit Eingabefeldern und einem Knopf zum Absenden. Der Browser schickt die Eingaben an den Server, das Programm baut eine SQL-Anweisung, schickt sie an das DBMS und erzeugt aus der Ergebnistabelle eine Webseite.

Gefährlich ist es, die Eingabe als Text in die Anweisung zu kleben (SQL-Injektion). Das Programm bildet SELECT * FROM schueler WHERE name = ’\texttt{SELECT * FROM schueler WHERE name = '}, hängt die Eingabe an und schließt mit einem Anführungszeichen. Wer x’ OR ’1’=’1\texttt{x' OR '1'='1} eingibt, erzeugt WHERE name = ’x’ OR ’1’=’1’\texttt{WHERE name = 'x' OR '1'='1'}: Die Bedingung ist immer wahr, alle Zeilen kommen zurück. Schutz bieten parametrisierte Anweisungen mit Platzhalter, WHERE name = ?\texttt{WHERE name = ?}. Die Eingabe wird getrennt als reiner Wert übergeben, nie als SQL-Code. Dazu kommt ein Datenbankbenutzer mit möglichst wenigen Rechten.

Häufige Fehler

COUNT(*) bei einem LEFT JOIN

"Ich zähle die Schüler je Kurs mit COUNT(*). Für den leeren Kurs kommt 0."

Richtig ist

Der LEFT JOIN\texttt{LEFT JOIN} erzeugt für den leeren Kurs eine Zeile mit NULL, die COUNT(*)\texttt{COUNT(*)} mitzählt. Das Ergebnis ist 1. Zähle eine Spalte der rechten Relation, COUNT(belegung.sid)\texttt{COUNT(belegung.sid)} überspringt NULL.

Zusammenfassung

  • Eine Abfrage verbindet Projektion (SELECT), Selektion (WHERE) und Sortierung (ORDER BY). DISTINCT entfernt doppelte Zeilen.

  • Ein JOIN verknüpft Relationen über Schlüssel. Der LEFT JOIN behält auch Zeilen ohne Partner und füllt sie mit NULL.

  • GROUP BY bildet Gruppen für Aggregatfunktionen. WHERE filtert vor, HAVING nach der Gruppierung.

  • Unterabfragen liefern einen Wert oder eine Spalte. DDL legt Strukturen fest, ein View ist eine gespeicherte Abfrage, DCL vergibt Rechte.

  • Jede Operation der Relationenalgebra hat eine Entsprechung in SQL. Die Projektion entspricht SELECT DISTINCT.

  • Parametrisierte Anweisungen verhindern bei Webformularen die SQL-Injektion.

Übungen

Aufgabe 1Numerisch

Mit den Daten der Lektion: Welche Zahl steht in der zweiten Spalte der einzigen Zeile von SELECT lid, SUM(gebuehr) FROM kurs GROUP BY lid HAVING COUNT(*) >= 2;

Aufgabe 2Multiple Choice

Welche Abfrage liefert die Schüler, die in keinem Kurs angemeldet sind?

Aufgabe 3Multiple Choice

Wie schützt man eine Webdatenbank am besten vor SQL-Injektion?

Aufgabe 4Freitext

Schreibe eine SQL-Abfrage, die für jede Lehrkraft den Namen und die Zahl ihrer Kurse liefert, auch 0 für Lehrkräfte ohne Kurs.

Aufgabe 5Multiple Choice

Welche SQL-Abfrage entspricht πtitel(σlid=7(Kurs))\pi_{\text{titel}}(\sigma_{\text{lid} = 7}(\text{Kurs}))?