Kapitel 8 Dr. Jérôme Kunegis SQL Continued WeST – Institute for Web Science & Technologies Lernziele • Syntax von SQL Anfragen • Erweiterte Konstrukte in SQL Abfragen: Aggregation, Gruppierung, rekursive Anfragen .. • Präzise Semantik von SQL Anfragen: Abbildung auf RA 2 Einfache SQL Anfragen "Grobsyntax": select_block { { UNION | INTERSECT | MINUS } [ALL] select_block ...} [ORDER BY result_column [ASC | DESC] {, result_column [ASC | DESC] …} mit select_block ::= SELECT [ALL | DISTINCT] {column | {expression [AS result_column]}} {, {column | {expression [AS result_column]}} …} FROM table [correlation_var] {, table [correlation_var] …} [WHERE search_condition] [GROUP BY column {, column …} [HAVING search_condition] ] 3 Oracle: Syntaxdiagramm 4 Mengenoperationen UNION UNION ALL INTERSECT MINUS Vereinigung von Mengen Vereinigung von Multimengen Schnittmenge Set-Minus (a.k.a. EXCEPT) Anfrage: Namen von allen Uni-Angehörigen SELECT Name FROM Assistenten UNION SELECT Name FROM Professoren UNION SELECT Name FROM Techniker; 5 Korrelationsvariablen (Tupelvariablen) Anfrage: alle Paare von Studenten, die in derselben Vorlesung sitzen SELECT s1.Name, s2.Name FROM Studenten s1, hören h1, Studenten s2, hören h2 WHERE h1.VorlNr = h2.VorlNr AND h1.MatrNr = s1.MatrNr AND h2.MatrNr = s2.MatrNr AND h1.MatrNr < h2.MatrNr; 6 Join "Grobsyntax" inner joins: ... FROM <table1> [INNER | NATURAL | CROSS] JOIN <table2> [ON <condition>] | [USING <column_name>, ... ], ... ... "Grobsyntax" outer joins: … FROM <table1> {LEFT | RIGHT | FULL [OUTER]} | UNION JOIN <table2> [ON <condition>] | [USING <column_name>, ... ] , ... ... 7 Inner Join Anfrage: welcher Professor bietet welche Vorlesungen an? SELECT p.Name, v.Name FROM Professoren p INNER JOIN Vorlesungen v ON p.PersNr = v.gelesenVon; SELECT p.Name, v.Name FROM Professoren p JOIN Vorlesungen v ON p.PersNr = v.gelesenVon; SELECT p.Name, v.Name FROM Professoren p, Vorlesungen v WHERE p.PersNr = v.gelesenVon; 8 Natural Join Anfrage: Welcher Student hört welche Vorlesung? SELECT Studenten.Name, Vorlesungen.Name FROM Studenten NATURAL JOIN hören NATURAL JOIN Vorlesungen; SELECT s.Name, v.Name FROM Studenten s, hören h, Vorlesungen v WHERE s.MatrNr = h.MatrNr AND h.VorlNr = v.vorlNr; 9 Cross Join Anfrage: alle Paare "Professor – Student" : SELECT Professoren.Name, Studenten.Name FROM Professoren CROSS JOIN Studenten; SELECT p.Name, s.Name FROM Professoren p, Studenten s; 10 Outer Joins: Left Outer Join SELECT p.PersNr, p.Name, f.PersNr, f.Note, f.MatrNr, s.MatrNr, s.Name FROM Professoren p LEFT OUTER JOIN ( prüfen f LEFT OUTER JOIN Studenten s ON f.MatrNr = s.MatrNr ) ON p.PersNr = f.PersNr ; p.PersNr p.Name f.PersNr f.Note f.MatrNr s.MatrNr s.Name 2126 Russel 2126 1 28106 28106 Carnap 2125 Sokrates 2125 2 25403 25403 Jonas 2137 Kant 2137 2 27550 27550 Schopenhauer 2136 Curie Ø Ø Ø Ø Ø … … … … … … … 11 Outer Joins: Right Outer Join SELECT p.PersNr, p.Name, f.PersNr, f.Note, f.MatrNr, s.MatrNr, s.Name FROM Professoren p RIGHT OUTER JOIN (prüfen f RIGHT OUTER JOIN Studenten s ON f.MatrNr = p.MatrNr) ON p.PersNr = f.PersNr; p.PersNr p.Name f.PersNr f.Note f.MatrNr s.MatrNr s.Name 2126 Russel 2126 1 28106 28106 Carnap 2125 Sokrates 2125 2 25403 25403 Jonas 2137 Kant 2137 2 27550 27550 Schopenhauer Ø Ø Ø Ø Ø 26120 Fichte … … … … … … … 12 Outer Joins: Full Outer Join SELECT p.PersNr, p.Name, f.PersNr, f.Note, f.MatrNr, s.MatrNr, s.Name FROM Professoren p FULL OUTER JOIN (prüfen f FULL OUTER JOIN Studenten s ON f.MatrNr = s.MatrNr) ON p.PersNr = f.PersNr; p.PersNr p.Name f.PersNr f.Note f.MatrNr s.MatrNr s.Name 2126 Russel 2126 1 28106 28106 Carnap 2125 Sokrates 2125 2 25403 25403 Jonas 2137 Kant 2137 2 27550 27550 Schopenhauer Ø Ø Ø Ø Ø 26120 Fichte … … … … … … … 2136 Curie Ø Ø Ø Ø Ø … … … … … … … 13 Bereichsanfragen und Mitgliedschaft in der Menge Anfrage: Studenten der ersten vier Semester SELECT * FROM Studenten WHERE Semester >= 1 AND Semester <= 4; SELECT * FROM Studenten WHERE Semester BETWEEN 1 and 4; SELECT * FROM Studenten WHERE Semester IN (1,2,3,4); 14 Subqueries • unkorellierte Subqueries: Anfrage: Professoren, die keine Vorlesungen anbieten SELECT Name FROM Professoren WHERE PersNr NOT IN ( SELECT gelesenVon FROM Vorlesungen ); • korrelierte Subqueries: Anfrage: Professoren, die keine Vorlesungen anbieten SELECT p.Name FROM Professoren p WHERE NOT EXISTS ( SELECT v.gelesenVon FROM Vorlesungen v WHERE v.gelesenVon = p.PersNr ); 15 String-Pattern-Matching Anfrage: Studenten, deren Name 'Schulz' ist: SELECT * FROM Studenten WHERE Name = 'Schulz'; Anfrage: Studenten, deren Name mit 'A' beginnt: SELECT * FROM Studenten WHERE Name LIKE 'A%'; Anfrage: Studenten mit Namen Mayer, Meyer, Mayor, …: SELECT * FROM Studenten WHERE Name LIKE 'M_y_r'; 16 "Quantifizierte" Subqueries Die Bedingung Wert θ ANY Menge mit θ ∈ {{=, ≠, <, >, ≤, ≥} ist erfüllt, wenn es in der Menge ein Element gibt, für das Wert θ Element gilt. (= ANY ist äquivalent zu IN) (SOME ist äquivalent to ANY) Die Bedingung Wert θ ALL Menge mit θ ∈ {=, ≠, <, >, ≤, ≥} ist erfüllt, wenn für alle Elemente der Menge gilt: Wert θ Element. (<> ALL ist äquivalent zu NOT IN) Die Bedingung EXISTS Menge ist erfüllt, wenn die Menge nicht leer ist (dies ist äquivalent zur Bedingung 0 < SELECT COUNT(*) FROM ...) Achtung: Wert θ ALL (query_returns_no_rows) = TRUE Wert θ ANY (query_returns_no_rows) = FALSE 17 "Quantifizierte" Subqueries Anfrage: Studenten im höchsten Semester: SELECT * FROM Studenten WHERE Semester >= ALL (SELECT Semester FROM Studenten); Anfrage: Studenten, für die keine Prüfungen erfasst sind: SELECT * FROM Studenten s WHERE NOT EXISTS (SELECT * FROM Prüfen p WHERE p.MatrNr = s.MatrNr); 18 Simulation allquantifizierter Suchprädikate SQL hat keinen Allquantor. Formulierungen der Anfrage: Wer hat alle vierstündigen Vorlesungen gehört? ∀ x. P(x) ⇔ ¬ ∃ x. ¬P(x) 19 Umsetzung des Allquantors in SQL Anfrage: Wer hat alle vierstündigen Vorlesungen gehört? SELECT s.MatrNr FROM Studenten s WHERE NOT EXISTS (SELECT * FROM Vorlesungen v WHERE v.SWS = 4 AND NOT EXISTS (SELECT * FROM hören h WHERE h.VorlNr = v.VorlNr AND h.MatrNr=s.MatrNr)); 20 Umsetzung des Allquantors in SQL: alternative Form Anfrage: Wer hat alle vierstündigen Vorlesungen gehört? SELECT s.MatrNr FROM Studenten s WHERE NOT EXISTS ( SELECT v.VorlNr FROM Vorlesungen v WHERE v.SWS = 4 MINUS SELECT h.VorlNr FROM hören h WHERE h.MatrNr = s.MatrNr ); 21 Aggregationsfunktionen "Grobsyntax": { MAX | MIN | AVG | SUM | COUNT } ( { ALL | DISTINCT } {column | expression | *} ) "Grobsemantik": Abbildung einer Menge skalarer Werte auf einen skalaren Wert 22 Aggregationsfunktionen: Beispiele (1) 1) Das höchste Semester unter allen Studenten: SELECT MAX (Semester) FROM Studenten; 2) Notendurchschnitt aller Prüfungsergebnisse: SELECT AVG (Note) FROM prüfen; 23 Aggregationsfunktionen: Beispiele (2) 3) Welche Studenten haben bereits einige Prüfungen hinter sich? SELECT DISTINCT MatrNr FROM prüfen; 4) Wieviele Studenten haben bereits Prüfungen hinter sich? SELECT COUNT (DISTINCT MatrNr) FROM prüfen ; 5) Wieviele Studenten sind im 15. Semester? SELECT COUNT (*) FROM Studenten WHERE Semester = 15; 6) Prüfungsleistungen, die über dem globalen Durchschnitt liegen: SELECT p.Note FROM prüfen p WHERE p.Note < (SELECT AVG (p1.Note) FROM prüfen p1); 24 Gruppierung Lehrpensum (Summe der Semesterwochenstunden) pro Professor: SELECT gelesenVon, SUM (SWS) FROM Vorlesungen GROUP BY gelesenVon; Lehrpensum der C4-Professoren, die überwiegend umfangreiche Lehrveranstaltungen anbieten (mit durchschnittlichem Umfang 3 SWS und mehr) SELECT gelesenVon, Name, SUM (SWS) FROM Vorlesungen, Professoren WHERE gelesenVon = PersNr AND Rang = 'C4' GROUP BY gelesenVon, Name HAVING AVG (SWS) >= 3; 25 Ausführen einer Anfrage mit GROUP BY SELECT gelesenVon, Name, SUM (SWS) FROM Vorlesungen, Professoren WHERE gelesenVon = PersNr AND Rang = 'C4' GROUP BY gelesenVon, Name HAVING AVG (SWS) >= 3; FROM Vorlesungen, Professoren VorlNr Titel 5001 Grundzüge 5041 Ethik ... ... 4630 Die 3 Kritiken SWS gelesen Von 4 4 ... 4 2137 2125 ... 2137 PersNr Name 2125 Sokrates 2125 Sokrates ... ... 2137 Kant Rang Raum C4 C4 ... C4 226 226 ... 7 WHERE gelesenVon = PersNr AND Rang = 'C4' 26 Ausführen einer Anfrage mit GROUP BY (2) WHERE gelesenVon = PersNr AND Rang = 'C4' VorlNr Titel SWS gelesen PersNr Von Name Rang Raum 5001 5041 5043 5049 4052 5052 Grundzüge Ethik Erkenntnistheorie Mäeutik Logik Wissenschaftstheorie 4 4 3 2 4 3 2137 2125 2126 2125 2125 2126 2137 2125 2126 2125 2125 2126 Kant Sokrates Russel Sokrates Sokrates Russel C4 C4 C4 C4 C4 C4 7 226 232 226 226 232 5216 4630 Bioethik Die 3 Kritiken 2 4 2126 2137 2126 2137 Russel Kant C4 C4 232 7 GROUP BY gelesenVon, Name 27 SWS gelesenVon PersNr Name VorlN Titel r 5041 Ethik 4 2125 2125 Sokrates 5049 Mäeutik 2 2125 2125 Sokrates 4052 Logik 4 2125 2125 Sokrates 5043 Erkenntnistheorie 3 2126 2126 Russel 5052 Wissenschaftstheo. 3 2126 2126 Russel 5216 Bioethik 2 2126 2126 Russel 5001 Grundzüge 4 2137 2137 Kant 4630 Die 3 Kritiken 4 2137 2137 Kant Rang Raum C4 226 C4 226 C4 226 C4 232 C4 232 C4 232 C4 7 C4 7 HAVING AVG (SWS) >= 3 VorlN r 5041 5049 4052 Titel Ethik Mäeutik Logik 5001 4630 Grundzüge Die 3 Kritiken SWS gelesenVon PersNr Name 4 2125 2125 Sokrates 2 2125 2125 Sokrates 4 2125 2125 Sokrates 4 4 2137 2137 2137 2137 Kant Kant Rang Raum C4 226 C4 226 C4 226 C4 C4 7 7 28 Ausführen einer Anfrage mit GROUP BY (4) HAVING AVG (SWS) >= 3 VorlN r 5041 5049 4052 Titel Ethik Mäeutik Logik 5001 4630 Grundzüge Die 3 Kritiken SWS gelesenVon PersNr Name 4 2125 2125 Sokrates 2 2125 2125 Sokrates 4 2125 2125 Sokrates 4 4 2137 2137 2137 2137 Kant Kant Rang Raum C4 226 C4 226 C4 226 C4 C4 7 7 SELECT gelesenVon, Name, SUM (SWS) gelesenVon Name sum (SWS) 2125 Sokrates 10 2137 Kant 8 29 Simulation allquantifizierter Suchprädikate durch count-Aggregation Allquantifizierung kann auch durch eine COUNT-Aggregation ausgedrückt werden Anfrage: Wer hat alle vierstündigen Vorlesungen gehört? SELECT h.MatrNr FROM hören h, Vorlesungen v WHERE v.SWS = 4 AND h.VorlNr = v.VorlNr GROUP BY h.MatrNr HAVING COUNT (*) = (SELECT COUNT (*) FROM Vorlesungen v1 WHERE v1.SWS = 4); 30 Count-Aggregation: Fehlerquellen Anfrage: Namen der Studenten, die alle vierstündigen Vorlesungen gehört haben Vorsicht: so geht das nicht… SELECT h.MatrNr, s.Name FROM hören h, Vorlesungen v, Studenten s WHERE v.SWS = 4 AND h.VorlNr = v.VorlNr AND h.MatrNr = s.MatrNr GROUP BY h.MatrNr HAVING COUNT (*) = (SELECT COUNT (*) FROM Vorlesungen v1 WHERE v1.SWS = 4); 31 Count-Aggregation: Fehlerquellen Anfrage: Namen der Studenten, die alle vierstündigen Vorlesungen gehört haben SELECT h.MatrNr, s.Name FROM hören h, Vorlesungen v, Studenten s WHERE v.SWS = 4 AND h.VorlNr = v.VorlNr AND h.MatrNr = s.MatrNr GROUP BY h.MatrNr, s.Name HAVING COUNT (*) = ( SELECT COUNT (*) FROM Vorlesungen v1 WHERE v1.SWS = 4 ); SQL erzeugt pro Gruppe ein Ergebnistupel. Deshalb müssen alle in der SELECT-Klausel aufgeführten Attribute - außer den aggregierten – auch in der GROUP BY-Klausel aufgeführt werden! 32 Behandlung von Nullwerten "Grobsemantik": Unbekannter Wert. Nullwerte können auch im Zuge der Anfrageauswertung entstehen (z.B. Outer Joins) manchmal überraschende Anfrageergebnisse, wenn Nullwerte vorkommen: SELECT COUNT(*) FROM prüfen WHERE Note > 2.0 OR Note <= 2.0 ; ist NICHT immer identisch mit SELECT COUNT(*) FROM prüfen ; Grund: wenn es Prüfungen gibt, deren Note-Attribut (noch) den Wert NULL hat, werden diese nicht mitgezählt ! 33 Auswertung bei Null-Werten In arithmetischen Ausdrücken werden Nullwerte propagiert: NULL + 1 = NULL NULL * 0 = NULL Die Behandlung von Strings + CLOBs ist systemspezifisch: Oracle: NULL || 'string' = 'string' MS SQL Server: NULL + 'string' = null MySQL: concat(NULL, 'string') = NULL (btw, || equivalent zu OR) SQL hat eine dreiwertige Logik mit TRUE, FALSE, UNKNOWN. Diesen Wert liefern Vergleichsoperationen zurück, wenn mindestens eines ihrer Argumente NULL ist. z.B. (Note <= 2.0) liefert UNKNOWN falls Note NULL ist 34 Gruppierung bei Null-Werten Bei einer Gruppierung wird null als ein eigenständiger Wert aufgefasst und in eine eigene Gruppe eingeordnet: SELECT Note, count(*) FROM prüfen GROUP BY Note Note 1.0 count(*) 25 1.3 94 … NULL … 248 35 Test auf Nullwert Anfrage: bisher unbenotete Prüfungsleistungen SELECT * FROM prüfen WHERE Note IS NULL; Anfrage: Professoren mit eigenem Büro SELECT * FROM Professoren WHERE Raum IS NOT NULL; 36 Rekursive Anfragen …für transitive Hüllen u.ä. Oracle Syntax: START WITH <condition> CONNECT BY [NOCYCLE] <condition> Anfrage: alle Vorlesungen, die man vor der Vorlesung 5041 (Ethik) besucht haben sollte SELECT Vorgänger FROM voraussetzen START WITH Nachfolger = 5041 CONNECT BY NOCYCLE PRIOR Vorgänger = Nachfolger AND Vorgänger != 5041 37 Built-in-Funktionen auf skalaren Werten Häufig produktspezifisch, z.B. • Stringmanipulation in Oracle: SELECT SUBSTR (Name, INSTR(Name, ' ')+1) FROM Studenten • Umwandlung eines Datums (Datentyp DATE) in einen String: SELECT TO_CHAR(SYSDATE, 'DY DD MONTH YYYY, HH24:MI:SS') FROM DUAL; etc. 38 Anhang Kapitel 8 Präzise Semantik von SQL-Anfragen 39 Abbildung SQL auf TRK und RA "Grobsemantik": SELECT A, B, ... FROM R, S, ..., T, ... WHERE F (so dass A, B, ... zu R, S, ... gehören, nicht aber zu T, ..., und F über R, S, ..., T, ... definiert ist) → RA: → TRK: 40 1. Abbildung SQL auf RA 41 Präzise Semantik einfacher SQL-Anfragen: Abbildung auf RA Voraussetzungen: 1) Vernachlässigung von Multimengen, Nullwerten u.ä. 2) Eindeutige Benennung von Tupelvariablen und Zuordnung von Attributen Vorgehensweise: Definition einer Abbildungsfunktion sql2ra: sql query → ra query von select_block-Konstrukten auf RA-Anfragen unter Verwendung der Funktion sql2ra’: sql where clause × ra query→ ra query von search_condition-Konstrukten auf RA-Ausdrücke sowie der Hilfsfunktion sql2ra-: sql where clause × ra query→ ra query mit sql2ra- [F](E) = E - π[sch(E)] (sql2ra’[F](E) ) .. Erweiterung auf Multirelationen relativ leicht möglich. 42 Abbildung SQL auf RA (1) sql2ra [ SELECT A1, A2, … FROM REL1 R1, REL2 R2, …, RELm Rm, TAB1 T1, TAB2 T2, …, TABk Tk WHERE F ] (so dass A1, A2, ..., An zu REL1, REL2, …, RELm gehören, nicht aber zu TAB1, …, TABk und F über REL1, ..., RELm, TAB1, …, TABk definiert ist ) 43 Abbildung SQL auf RA (2) sql2ra [ select-block1 UNION select-block2 ] mit select-block1: SELECT A1, A2, … FROM REL1 R1, …, RELm Rm, TAB1 T1, …, TABk Tk WHERE F und select-block2: SELECT B1, B2, ... FROM SET1 S1, ..., SETm’ Sm’, PAR1 P1, ..., PARk’ Pk’ WHERE G .. mit ggf. notwendigen Umbenennungen von Attributen 44 Abbildung SQL auf RA (2) 45 Abbildung SQL auf RA (4) sql2trc’ [Ri.Aj IN subquery] (so dass subquery die Form SELECT Qk.C FROM QUELL1 Q1, ..., QUELLm’ Qm’ WHERE H hat) 46 Abbildung SQL auf RA (5) sql2trc’ [Ri.Aj θ ANY subquery] = (so dass subquery die Form SELECT Qk.C FROM QUELL1 Q1, ..., QUELLm’ Qm’ WHERE H hat) 47 Abbildung SQL auf RA (6) sql2trc’ [Ri.Aj θ ALL subquery] = (so dass subquery die Form SELECT Qk.C FROM QUELL1 Q1, ..., QUELLm’ Qm’ WHERE H hat) 48 Abbildung SQL auf RA (7) sql2trc’ [EXISTS subquery] = (so dass subquery die Form SELECT C1, C2, ... FROM QUELL1 Q1, ..., QUELLm’ Qm’ WHERE H hat) 49 Abbildung SQL auf RA: Beispiel query = SELECT s.MatrNr, s.Name FROM Studenten s WHERE s.Semester > 5 AND NOT EXISTS (SELECT * FROM hören h, Vorlesungen v WHERE v.SWS = 4 AND v.vorlNr = h.vorlNr AND s.MatrNr = h.MatrNr) 50 3. Semantik der Gruppierung 51 Abbildung SQL auf RA (1) sql2ra [ SELECT A', f(B) FROM … WHERE … GROUP BY A ] (wobei A' ⊆ A gelten muss) 52 Abbildung SQL auf RA (1) sql2ra [ SELECT A', f(B) FROM … WHERE … GROUP BY A HAVING cond(A,g(C))] (wobei A' ⊆ A gelten muss) MRA-Programm 53