Was wäre, wenn in der Anfrage 'Ute' nicht in Hochkommas stünde?
Das ginge trotzdem
Das wäre kein wohlgeformtes SQL
Dann wäre damit die Variable Ute gemeint
Dann wäre damit die Spalte Ute gemeint
https://frage.space
Kommentare
SELECT * FROM t -- Ein Doppelminus leitet einen Kommentar ein
SELECT * FROM t
--WHERE x = 5
SELECT kundennummer /*, email*/ FROM kunden
DDL: CREATE, ALTER, DROP
44
Anlegen, Verändern und Entfernen von Datenbankobjekten (Tabellen, Sichten, Funktionen, ...)
CREATE TABLE personen (pid INT, name VARCHAR(500), geboren DATE);
CREATE TABLE
Name der zu erstellenden Tabelle
Spalten in Klammern, Komma-getrennt
Zu jeder Spalte: Name, Datentyp, evtl. Spaltenoptionen
Datentypen
39-41
Datentyp
Alias
Beschreibung
Beispiel
INTEGER
INT
Ganze Zahl
-217
DECIMAL(p,s)
NUMERIC
Zahl mit p Stellen, davon s nach dem Dezimalpunkt
DECIMAL(5,2) -149.99
DOUBLE
REAL
Fließkommazahl (nicht exakt)
-15.127E-2
CHARACTER(l)
CHAR
Zeichenkette mit fixer Länge l
CHAR(3) 'AB '
CHARACTER VARYING(l)
VARCHAR
Zeichenkette mit max. Länge l
VARCHAR(3) 'AB'
DATE
Datum (Jahr, Monat, Tag)
'2020-11-18'
TIMESTAMP
Zeitstempel (Datum und Uhrzeit)
'2020-11-18 14:37:52.681'
CREATE TABLE - Spaltenoptionen
45, 47
CREATE TABLE kunden (
kundennummer INT PRIMARY KEY, name VARCHAR(100) NOT NULL,
email VARCHAR(500) CHECK (email LIKE '%@%') UNIQUE,
passwort CHAR(32), land VARCHAR(100) DEFAULT 'Deutschland',
geworben_von INT REFERENCES kunden(kundennummer));
Constraints (Integritätsbedingungen):
PRIMARY KEY: Primärschlüssel
NOT NULL: Verbot von NULL-Werten
CHECK: Bedingung für akzeptierte Werte
UNIQUE: Eindeutigkeit
DEFAULT: Standardwert
REFERENCES: Fremdschlüsselreferenz
NULL / NOT NULL
NULL (Standard)
CREATE TABLE kunden (/* ... */, name VARCHAR(100) NULL)
NULL-Werte sind in der Spalte erlaubt.
NOT NULL
CREATE TABLE kunden (/* ... */, name VARCHAR(100) NOT NULL)
CREATE TABLE produkte (
produktnummer INT PRIMARY KEY,
bezeichnung VARCHAR(100) NOT NULL, preis DECIMAL(9,2),
hersteller VARCHAR(50) REFERENCES hersteller(firma)
ON DELETE SET NULL ON UPDATE CASCADE);
Was soll passieren, wenn ein Hersteller gelöscht wird, von dem es noch Produkte gibt? (Analog dazu: Was passiert, wenn man ihn umbenennt? - ON UPDATE)
ON DELETE CASCADE: Alle Produkte auch löschen
ON DELETE SET NULL / SET DEFAULT: NULL / Default-Wert setzen
ON DELETE RESTRICT: Löschen verbieten
ON DELETE NO ACTION (Standardverhalten): erst mal abwarten
Studierende(FBName) REFERENCES Fachbereich(FBName) ON DELETE CASCADE
Professoren(FBName) REFERENCES Fachbereich(FBName) ON DELETE CASCADE
Prüfungen(MatrNr) REFERENCES Studierende(MatrNr) ON DELETE CASCADE
Prüfungen(ProfNr) REFERENCES Professoren(MatrNr)
Fachbereich wird gelöscht ⇒ alle Studierenden in diesem werden gelöscht ⇒ Die Prüfungen der Studierenden werden gelöscht. Professoren werden gelöscht. OK!
INSERT INTO produkte(preis, bezeichnung)
VALUES (4.99, 'Katzenfutter')
Spaltennamen weglassen:
INSERT INTO produkte VALUES (88, 'Katzenfutter', 4.99, NULL)
Nachteile: Schwerer verständlich zu lesen, man muss auf die korrekte Reihenfolge achten, man darf keine Spalte vergessen, in der Zukunft könnten sich die Spalten ändern.
UPDATE
54
UPDATE produkte SET preis = 5.99 WHERE produktnr = 88
UPDATE produkte
SET preis = 5.99, bezeichnung = 'Spezial-Katzenfutter'
WHERE produktnr = 88
Was wird geändert, wenn man kein WHERE-Prädikat angibt?
Nur die erste Zeile
Alle Zeilen
Gar nichts
https://frage.space
UPDATE produkte SET preis = preis+1
UPDATE produkte SET preis = preis * 1.1
DELETE / TRUNCATE TABLE
55
DELETE FROM produkte WHERE produktnr = 88
DELETE FROM produkte WHERE hersteller = 'Monsterfood'
AND preis < 1.00
DELETE FROM produkte
TRUNCATE TABLE produkte
Was ist der Unterschied zwischen TRUNCATE TABLE und DROP TABLE?
TRUNCATE ist schneller
TRUNCATE löscht die Tabelle aus dem Metadaten-Katalog der Datenbank
TRUNCATE löscht nur die Daten, die Tabelle ist noch da
Es gibt keinen
https://frage.space
SELECT
SELECT H.land, COUNT(*) AS anzahl, AVG(P.preis) AS avg_preis
FROM hersteller H LEFT JOIN produkte P ON H.firma = p.hersteller
WHERE P.preis > 3
GROUP BY h.land
HAVING COUNT(*) < 5
ORDER BY COUNT(*)
"Zeige mir für jedes Land, in welchem weniger als fünf Produkte, die mehr als 3 EUR kosten, hergestellt wurden, die Anzahl der Produkte sowie die Durchschnittspreise an, aufsteigend sortiert nach der Anzahl.
SELECT: Projektion
FROM: Tabellen und Joins
WHERE: Selektion
GROUP BY: Zeilen gruppieren
HAVING: Selektion nach der Gruppierung
ORDER BY: Ergebnis sortieren
SELECT <spalten> FROM <tabelle>
57
SELECT bezeichnung, preis, round(preis * 1.15, 2) AS preis_usd
FROM produkte
Was macht dieses SELECT?
Selektion
Projektion ohne Duplikateliminierung
Kreuzprodukt
Weder noch
https://frage.space
SELECT * FROM <tabelle>
SELECT * FROM produkte
SELECT DISTINCT
SELECT hersteller
FROM produkte
SELECT DISTINCT hersteller
FROM produkte
WHERE
58
σ
SELECT * FROM produkte WHERE preis > 3
SELECT * FROM produkte WHERE preis >= 3 AND preis <= 9
SELECT * FROM produkte WHERE preis BETWEEN 3 AND 9
LIKE-Prädikat
59
SELECT * FROM produkte WHERE bezeichnung = 'Müsliriegel'
SELECT * FROM produkte WHERE bezeichnung LIKE 'M%'
SELECT * FROM produkte WHERE bezeichnung LIKE '%-%'
SELECT * FROM produkte WHERE bezeichnung LIKE 'M_sliriegel'
Was wird durch die untere Anfrage gefunden?
Masliriegel
Muesliriegel
Msliregel
Keines davon
https://frage.space
NULL-Werte
SELECT * FROM produkte WHERE hersteller IS NULL
SELECT * FROM produkte WHERE hersteller IS NOT NULL
hersteller = NULL ist...
immer true
immer false
true, wenn hersteller NULL ist
false, wenn hersteller NULL ist
https://frage.space
Kreuzprodukt
×
SELECT * FROM produkte, hersteller
Join
⋈
SELECT * FROM produkte, hersteller
WHERE produkte.hersteller = hersteller.firma
<tabelle> JOIN <tabelle> ON <präd.>
61-62
SELECT * FROM produkte JOIN hersteller
ON produkte.hersteller = hersteller.firma
Tabellen-Alias
SELECT * FROM produkte P JOIN hersteller H
ON P.hersteller = H.firma
LEFT/RIGHT/FULL [OUTER] JOIN
63
SELECT * FROM produkte P LEFT JOIN hersteller H
ON P.hersteller = H.firma
JOIN ... USING(...)
SELECT P.*, B.sterne
FROM produkte P JOIN bewertungen B USING(produktnr)
Welche Aussage ist falsch?
Die Anfrage entspricht einem äußeren Verbund
Die Anfrage entspricht einem natürlichen Verbund
Die Anfrage entspricht ON P.produktnr = B.produktnr
Die Anfrage funktioniert nur, wenn beide Tabellen die Spalte produktnr haben
https://frage.space
Aggregatfunktionen
64
COUNT: Anzahl
SUM: Summe
AVG: Durchschnittswert
MIN: Kleinster Wert
MAX: Größter Wert
...
Aggregatfunktion in der SELECT-Liste ohne GROUP BY-Klausel ⇒ die ganze Tabelle bildet eine große Gruppe ⇒ es kommt nur eine Zeile raus.
COUNT
SELECT COUNT(*)
FROM produkte
SELECT COUNT(hersteller)
FROM produkte
SELECT COUNT(DISTINCT hersteller) FROM produkte
SUM / AVG / MIN / MAX
SELECT SUM(preis), AVG(preis), MIN(preis), MAX(preis)
FROM produkte
GROUP BY
65
SELECT hersteller, COUNT(*), AVG(preis)
FROM produkte
GROUP BY hersteller
Wie viele Zeilen kommen hier heraus?
0
1
So viele, wie es verschiedene Werte in der hersteller-Spalte gibt
So viele, wie es Zeilen in der Produkte-Tabelle gibt
https://frage.space
GROUP BY
66
SELECT hersteller, preis, COUNT(*)
FROM produkte
GROUP BY hersteller, preis
HAVING
69
SELECT hersteller, AVG(preis)
FROM produkte
GROUP BY hersteller
HAVING COUNT(*) >= 2
Sub-Anfragen
67-68
SELECT hersteller, avg_preis FROM (
SELECT hersteller, COUNT(*) AS anzahl, AVG(preis) AS avg_preis
FROM produkte GROUP BY hersteller
) P WHERE anzahl >= 2
SELECT * FROM produkte
WHERE preis = (SELECT MAX(preis) FROM produkte)
SELECT * FROM produkte P1
WHERE preis = (SELECT MAX(preis) FROM produkte P2
WHERE P2.hersteller = P1.hersteller)
CTE: Common Table Expressions
90
WITH ... AS (SELECT ...) SELECT ...
WITH monsterfood_produkte AS
(SELECT * FROM produkte WHERE hersteller = 'Monsterfood')
SELECT count(*) FROM monsterfood_produkte
WITH monsterfood_produkte AS
(SELECT * FROM produkte WHERE hersteller = 'Monsterfood')
SELECT * FROM monsterfood_produkte
WHERE preis = (SELECT max(preis) FROM monsterfood_produkte)
ORDER BY
70
"Tabellen haben keine Ordnung, Ergebnisse schon."
ASC: aufsteigend sortieren (Standard)
DESC: absteigend sortieren
SELECT * FROM produkte ORDER BY preis
Wenn zwei Produkte den gleichen Preis haben, welches kommt dann zuerst?
Das mit der kleinsten produktnr
Das, was zuerst eingefügt wurde
Das, was zuletzt eingefügt wurde
Keine Ahnung
https://frage.space
ORDER BY
"Tabellen haben keine Ordnung, Ergebnisse schon."
SELECT * FROM produkte
ORDER BY hersteller NULLS LAST, preis DESC
LIMIT
71
SQL Standard (und DB2):
SELECT * FROM produkte ORDER BY preis DESC
FETCH FIRST 5 ROWS ONLY
PostgreSQL, MySQL, MariaDB, SQLite, ...
SELECT * FROM produkte ORDER BY preis DESC
LIMIT 5
LIMIT mit OFFSET
SELECT * FROM produkte ORDER BY preis DESC
LIMIT 2, 5
SELECT * FROM produkte ORDER BY preis DESC
LIMIT 5 OFFSET 2
SELECT
SELECT H.land, COUNT(*) AS anzahl, AVG(P.preis) AS avg_preis
FROM hersteller H JOIN produkte P ON H.firma = p.hersteller
WHERE P.preis > 3
GROUP BY h.land
HAVING COUNT(*) < 5
ORDER BY COUNT(*)
"Zeige mir für jedes Land, in welchem weniger als fünf Produkte, die mehr als 3 EUR kosten, hergestellt wurden, die Anzahl der Produkte sowie die Durchschnittspreise an, aufsteigend sortiert nach der Anzahl.
Ich will im Ergebnis auch sehen, dass es z. B. aus Österreich 0 solche Produkte gibt!
SELECT mit OUTER JOIN
73
SELECT H.land, COUNT(*) AS anzahl, AVG(P.preis) AS avg_preis
FROM hersteller H LEFT JOIN produkte P ON p.hersteller = H.firma
WHERE P.preis > 3
GROUP BY h.land HAVING COUNT(*) < 5 ORDER BY COUNT(*)
Problem: WHERE-Prädikat preis > 3 wird nach dem äußeren Verbund ausgeführt, schmeißt also die gewünschten Zeilen mit NULL-Werten wieder raus.
SELECT /****/
WHERE P.preis > 3 OR P.produktnr IS NULL
SELECT H.land, COUNT(*) AS anzahl, AVG(P.preis) AS avg_preis
FROM hersteller H
LEFT JOIN (SELECT * FROM produkte WHERE preis > 3) P
ON p.hersteller = H.firma
GROUP BY h.land HAVING COUNT(*) < 5 ORDER BY COUNT(*)
74-75
⋃
UNION
Aus welchen Ländern sind unsere Kunden und Hersteller?
SELECT land FROM kunden
UNION
SELECT land FROM hersteller
Was muss für die Spalten (hier: land) der beiden Teilanfragen gelten?
Sie müssen gleich heißen
Es müssen gleich viele sein
Beides
Weder noch
https://frage.space
Bei Mengenoperationen ohne das Stichwort ALL wird nach UNION, INTERSECT und EXCEPT eine Duplikateliminierung vorgenommen.
UNION ALL
Aus welchen Ländern sind unsere Kunden und Hersteller?
SELECT land FROM kunden
UNION ALL
SELECT land FROM hersteller
76
INTERSECT
⋂
In welchen Ländern gibt es Kunden und Hersteller?
SELECT land FROM kunden
INTERSECT
SELECT land FROM hersteller
SELECT land FROM kunden
INTERSECT ALL
SELECT land FROM hersteller
76
EXCEPT (MINUS)
\
In welchen Ländern gibt es Kunden, aber keine Hersteller?
SELECT land FROM kunden
EXCEPT
SELECT land FROM hersteller
SELECT land FROM kunden
EXCEPT ALL
SELECT land FROM hersteller
Das EXISTS-Prädikat
78
∃
Eingabe: Eine SELECT-Anfrage
Ausgabe:
TRUE, wenn die Anfrage mind. 1 Zeile liefert
FALSE, wenn die Anfrage die leere Menge liefert
SELECT * FROM hersteller H
WHERE EXISTS
(SELECT * FROM produkte P WHERE p.hersteller = H.firma)
Was liefert diese Anfrage?
Hersteller, von denen es Produkte gibt
Produkte, die einen Hersteller haben
Hersteller, von denen es keine Produkte gibt
Produkte mit Hersteller NULL
https://frage.space
NOT EXISTS
∄
Von welchen Herstellern gibt es keine Produkte?
SELECT * FROM hersteller H
WHERE NOT EXISTS
(SELECT * FROM produkte P WHERE p.hersteller = H.firma)
Das IN-Prädikat
79
∈
Eingabe: Ein Ausdruck und entweder eine Werte-Liste oder eine SELECT-Anfrage
Ausgabe:
TRUE, wenn der Ausdruck enthalten ist
FALSE, wenn der Ausdruck nicht enthalten ist
SELECT * FROM hersteller H
WHERE firma IN ('Holzkopf', 'Monsterfood')
Das IN-Prädikat
∉
SELECT * FROM hersteller H
WHERE firma IN (SELECT hersteller FROM produkte)
SELECT * FROM hersteller H
WHERE firma NOT IN
(SELECT hersteller FROM produkte WHERE hersteller IS NOT NULL)
CAST: Typumwandlung
80
CAST(ausdruck AS datentyp)
SELECT preis, CAST(preis AS INT), CAST(preis AS VARCHAR(50))
FROM produkte
CASE WHEN
81
CASE WHEN ... THEN ... ELSE ... END
SELECT bezeichnung, preis,
CASE WHEN preis < 1 THEN 'billig'
WHEN preis < 5 THEN 'mittel'
ELSE 'teuer' END
FROM produkte
CASE WHEN
CASE ... WHEN ... THEN ... ELSE ... END
SELECT bezeichnung, preis,
CASE preis WHEN 0 THEN 'kostenlos' ELSE preis END
FROM produkte ORDER BY preis
Dummy-Tabelle DUAL
81
In einigen DBMS (Oracle, DB2, ...) gibt es die Tabelle DUAL.
SELECT * FROM dual
Praktisch zum Rechnen und Ausprobieren von Funktionen:
SELECT 5*3, CASE WHEN 7>4 THEN 'Ja' ELSE 'Nein' END FROM DUAL
SELECT ohne FROM in PostgreSQL
SELECT 5*3, CASE WHEN 7>4 THEN 'Ja' ELSE 'Nein' END
Wie viele Tage sind noch bis Weihnachten?
SELECT DATE '2020-12-25' - CURRENT_DATE
Wie kann man den Spalten dieser Anfrage sinnvolle Namen geben?
SELECT DATE '2020-12-25' - CURRENT_DATE anzahl_tage
SELECT DATE '2020-12-25' - CURRENT_DATE : anzahl_tage
SELECT DATE '2020-12-25' - CURRENT_DATE AS anzahl_tage
RENAME column DATE '2020-12-25' - CURRENT_DATE AS anzahl_tage