SELECT - Klaus Kusche

Werbung
Datenbanken
und SQL
Klaus Kusche, 2013-
Was ist eine
Datenbank ???
(hier nur “Relationale” Datenbank:
Es gibt auch objektorientierte DB, Volltext-DB, ...)
Datenbank vs. DBMS
Unterscheide:
●
Datenbank = “Die Daten an sich”
==> Ansammlung von Tabellen
●
DBMS = “Data Base Management System”
==> Die Software, die diese Daten / Tabellen
erzeugt, verwaltet, durchsucht, ...
Bekannte DBMS
●
Oracle: Kommerziell, Marktführer
●
DB/2: Kommerziell, von IBM
●
MS SQL Server: Kommerziell, von Microsoft
●
MySQL (MariaDB): Open Source, primär für WWW
Eher Spielzeug, ist noch nicht in allen Punkten “echte” DB!
●
PostgreSQL: Open Source, “große” DB
De facto SQL-Standard-Referenzimplementierung!
●
SQLite: Open Source, “kleine” DB (z.B. in Firefox)
Als Library zu einem Programm, kein eigener Server!
Alles in einem File, im Betrieb oft komplett im RAM.
Nicht DBMS
●
Excel:
Fast alle Eigenschaften einer DB fehlen!
●
Access:
Von der Daten-Logik her fast eine Datenbank,
vom praktischen Betrieb her nicht...
Eigenschaften von DB & DBMS
“Wie unterscheidet sich ein DBMS
von Excel / Access?”
●
Datendarstellung
●
Größe
●
Zugriff
●
Transaktionen und Mehrbenutzer-Fähigkeit
●
Datensicherheit
Datendarstellung (1)
●
●
In ein oder mehreren Tabellen
Spalten sind nicht nummeriert,
sondern haben einen Namen (==> Reihenfolge egal)
und einen Typ (Int, Text, Datum, Bool, Binärdaten, ...)
Wird beides beim Erzeugen der Tabelle festgelegt!
●
Zeilen sind nicht nummeriert,
sondern ohne bestimmte Reihenfolge
(interne Reihenfolge ist beliebig, nicht nach außen sichtbar)
Jederzeit beliebig Einfügen und Löschen möglich!
Datendarstellung (2)
●
Zugriff auf bestimmte Zeilen mittels Inhalt, z.B.:
“Gib mir alle Zeilen, bei denen die Spalte
'Geburtsdatum' zwischen 1990 und 2000 liegt ...”
●
Reihenfolge / Sortierung nach außen
auf Wunsch auch nach Inhalt, z.B.:
“... und sortiere sie nach dem 'Nachnamen'!”
●
Damit beides schneller geht:
Vorab Deklaration bestimmter Spalten als
(Primär- / Sekundär-) Schlüssel bzw. Index
Typische Größen
●
●
●
Tabellen:
Ein paar Dutzend bis einige 1000 (SAP: > 20000 !)
Zeilen pro Tabelle:
Ganz wenige (z.B. Konfigurations-Tabellen)
bis viele Millionen (z.B. Konten, Bank-Buchungen)
Datenmenge insgesamt:
Einige KB bis einige TB
==> Alles im Speicher halten geht nicht!
==> Der Reihe nach durchsuchen dauert zu lange!
==> “Clevere” Speicherung auf Platte nötig!
==> Zugriff nur über DBMS, nicht direkt (mit Editor o.ä.) lesbar!
Zugriff (1)
●
●
Nicht direkt (mit Zeilen- & Spaltennummer)
auf einzelne Felder...
sondern als “Frage- und Antwort-Spiel”:
“Gib mir ...”, “Lösche ...”, “Füge ... neu dazu”, ...
●
Programmiersprache für die Fragen:
SQL
= Structured Query Language
(schaut ganz anders aus als normale Programmiersprachen,
teilweise fast wie Englisch lesbar)
Zugriff (2)
SQL erlaubt die Beschreibung u.a. von
●
Suche bzw. Zeilen- und Spaltenauswahl,
Pattern Matching (“Wildcards”)...
●
Sortierung und Gruppierung
●
Verknüpfung der Daten aus mehreren Tabellen
●
Berechnungen auf dem Ergebnis
(Min & Max oder Summe einer Spalte, Anzahl der Treffer, ...)
==> Das passiert alles schon im DBMS selbst!
==> Das Programm, die die Daten braucht / anzeigt / ...,
wird dadurch viel einfacher!
SQL
●
Entstanden um / vor 1980
1979: Erste Oracle-Version mit SQL
●
Genormt (ANSI, ISO) seit 1986
●
Heute meist verwendeter Standard:
SQL-92 oder SQL-99
●
Seitdem vor allem um XML erweitert,
aktuell SQL-11
Zugriff technisch (1)
Das DBMS ist ein eigener Server:
●
●
●
Läuft ständig, oft auf eigener Maschine
Horcht am Netz auf SQL-Requests
==> Remote-Zugriff möglich!
==> Meist Anmeldung (Benutzer & Passwort) nötig,
Benutzer mit unterschiedlichen Rechten!
Enthält u.a. SQL-Interpreter und -Optimizer:
"In welcher Reihenfolge muss ich wie
auf welche Tabellen zugreifen, um die Abfrage
möglichst schnell zu beantworten?"
Zugriff technisch (2)
Dazu gehören verschiedene Clients ...
●
... als Libraries für verschiedene Programmiersprachen
(PHP, C/C++, Java, ...):
Absetzen von SQL-Abfragen
aus anderen Programmen heraus
●
... als eigenständiges GUI- oder Commandline-Tool:
Händisches Eintippen von SQL-Befehlen,
Direktes Anzeigen des Ergebnisses als Tabelle.
Weitere Komponente eines DBMS:
●
Administrations-Tools: Backup, Export/Import, ...
Im praktischen Betrieb...
... gibt es viele Herausforderungen:
●
Wenn mehrere Benutzer gleichzeitig zugreifen:
Änderungen geraten sich gegenseitig in die Quere?!
(ein Benutzer sieht “halbe” neue Daten eines anderen?)
●
Bei Absturz, Stromausfall, ...:
Danach “halbe” Änderungen in der Datenbank?!
(manche Änderungen betreffen Millionen Zeilen!)
●
Bei Erkennen eines Problems am Ende
mehrerer zusammengehörender SQL-Befehle:
Was ist mit den schon erfolgreichen Befehlen davor?
Das Transaktions-Konzept (1)
Eine Transaktion umfasst
mehrere aufeinanderfolgende,
logisch zusammengehörende SQL-Befehle
eines Benutzers (einer Session, ...):
Alle Zugriffe / Änderungen, die nötig sind,
um eine Buchung, Bestellung, ... komplett auszuführen
(beginnend von den ursprünglichen Daten,
bis die neuen Daten alle vollständig eingetragen sind).
In EDV-Deutsch: Alle SQL-Befehle, die nötig sind,
um von einem konsistenten Zustand der Daten
zum nächsten konsistenten Zustand zu kommen.
Das Transaktions-Konzept (2)
Eine Transaktion kann
●
entweder erfolgreich abgeschlossen werden:
“COMMIT” =
“Speichere alle Änderungen dieser Transaktion endgültig
und mach sie für alle anderen sichtbar!”
●
oder komplett zurückgenommen werden:
“ROLLBACK” =
“Mach alle Änderungen dieser Transaktion rückgängig,
als ob es die Befehle nie gegeben hätte!”
Das ACID-Prinzip (1)
●
Änderungen sind atomar:
“Alles oder nichts”
==> Es sind nie “halbe” Transaktionen sichtbar!
●
Die Datenbank ist (c)konsistent:
Nach jeder Transaktion ist die Datenbank
in “sauberem” Zustand:
Die Daten in allen Tabellen
passen inhaltlich wieder zueinander.
Das ACID-Prinzip (2)
●
Jede Transaktion läuft isoliert:
... als ob sie die Datenbank für sich allein hätte:
Keine gegenseitige Beeinflussung!
Eine Transaktion sieht von Anfang bis Ende
denselben Datenbank-Inhalt und bekommt von anderen,
gleichzeitigen laufenden Transaktionen nichts mit.
●
Jedes erfolgreiche COMMIT ist beständig (durable):
Auch wenn die Datenbank gleich danach abstürzt
(oder die Platte kaputtgeht),
bleiben die Daten erhalten!
Wie geht das? (1)
Jedes “echte” DBMS verwaltet
zwei Platten-Speicherbereiche
(hoffentlich auf zwei verschiedenen Platten):
●
Die eigentliche Datenbank:
Enthält die gerade aktuellen Daten
(nicht unbedingt immer konsistent)
●
Den Log:
Enthält der Reihe nach alle Änderungen und Commits
(seit dem letzten Backup, jeweils Alt- und Neu-Daten)
Laufend geschrieben, COMMIT wartet bis der Log auf Platte ist!
Wie geht das? (2)
●
ROLLBACK:
“Schau im Log nach,
was du alles rückgängig machen musst!”
●
Plattencrash:
“Roll forward” = “Nimm das letzte Daten-Backup,
und hole alle Änderungen seitdem aus dem Log nach!”
●
Datenbank-Crash:
“Prüfe beim nächsten Start den Log:
Mach alle unfertigen Transaktionen rückgängig und prüfe,
ob alle fertigen Transaktionen komplett gespeichert sind!”
Was gehört zu
SQL ?
Arten von SQL-Befehlen (1)
Auslesen
von Daten
(incl. Suche, Sortierung, Gruppierung,
Verknüpfung von Daten mehrerer Tabellen...)
SELECT ...
FROM ...
WHERE ...
(was?)
(aus welcher Tabelle?)
(Suchbedingung)
(ev. plus ORDER BY ... GROUP BY ... usw.)
(auch: Kopieren von Daten in eine andere Tabelle)
Arten von SQL-Befehlen (2)
Einfügen / Ändern / Löschen
von Daten
INSERT ...
INTO ...
(was?)
(in welche Tabelle?)
UPDATE ...
SET ...
WHERE ...
(welche Tabelle?)
(welche Spalten auf welche Werte?)
(in welchen Zeilen?)
DELETE FROM ... (in welcher Tabelle?)
WHERE ... (welche Zeilen?)
Arten von SQL-Befehlen (3)
Anlegen
von Tabellen
CREATE TABLE ... (Tabellenname)
( ... )
(Spalten-Definitionen)
(auch: Festlegen der Schlüssel-Spalte usw.)
CREATE VIEW ...
(ähnlich für “virtuelle” Tabellen)
CREATE INDEX ... (Anlegen eines Such-Index
auf einer bestehenden Tabelle)
Arten von SQL-Befehlen (4)
Ändern
von Tabellen
ALTER TABLE ...
ADD ...
DROP ...
MODIFY ...
CHANGE ...
(Tabellenname)
(Spalte dazu)
(Spalte löschen)
(Spaltentyp usw. ändern)
(Spaltenname ändern)
ALTER INDEX ...
(analog für Index)
Arten von SQL-Befehlen (5)
Löschen
von Tabellen
DROP TABLE ... (Tabellenname)
(löscht die Tabelle mitsamt allen Daten)
DROP INDEX ... (analog für Index)
DROP VIEW ... (analog für View)
TRUNCATE TABLE ... (Tabellenname)
(löscht alle Daten, aber nicht die Tabelle selbst)
Das ist (fast) alles und was ist daran so schwer?
Die Details
des SELECT !
SELECT Schlüsselwörter usw.
SELECT
DISTINCT
WHERE
AND OR
IN
BETWEEN
LIKE
ORDER BY
COUNT
GROUP BY
HAVING
ALIAS
JOIN
FULL JOIN
UNION
UNION ALL
INTERSECT
MINUS
SUBSTRING
CASE
...
Funktionen,
Unterabfragen,
Kaskadierungen, ...
Einfaches SELECT
SELECT * FROM Schueler
Gib alle Zeilen und alle Spalten
der Tabelle Schueler aus.
SELECT Vorname, Nachname, GebDat
FROM Schueler
Wie oben, aber nur die angegebenen Spalten.
SELECT DISTINCT Klasse FROM Schueler
Nur Spalte Klasse, doppelte Einträge weglassen
= Liste aller Klassen.
Sortierte Ausgabe: ORDER BY
SELECT * FROM Schueler
ORDER BY Nachname
Nach Nachname sortiertes Ergebnis.
SELECT Vorname, Nachname, GebDat
FROM Schueler ORDER BY 3 DESC
Nach der 3. Ergebnis-Spalte (GebDat)
absteigend (“descending”) sortiertes Ergebnis.
SELECT * FROM Schueler
ORDER BY Klasse, Note
Zuerst nach Klasse, bei gleicher Klasse nach Note...
Abkürzungen für Tabellen: AS
SELECT S.Note, S.Nachname
FROM Schueler AS S
ORDER BY S.Note DESC
S wird als Abkürzung (Alias)
für die Tabelle Schueler definiert
S.Note heißt
“die Spalte Note der Tabelle S (= Schueler)”
Sinnvoll ...
●
bei Befehlen über mehrere Tabellen
●
damit der SQL-Interpreter die Spalten schneller findet
Spalten benennen und berechnen
SELECT Nachname, GebDat AS Geburtstag
FROM Schueler
Spaltenüberschrift “Geburtstag” statt “GebDat”.
SELECT Semester, 1800 AS Semestergebuehr,
Semester * 1800 AS Gesamtbetrag
FROM Schueler
1. Spalte “Semester” = Semester aus der Tabelle,
2. Spalte “Semestergebuehr” = Wert fix 1800
3. Spalte “Gesamtbetrag” = Wert aus 1. Spalte mal 1800
Fallunterscheidung: CASE (1)
●
Variante 1: Vergleich mit konstanten Werten
SELECT Vorname, Nachname,
CASE Semester
WHEN 1 THEN 'Anfänger'
WHEN 2 THEN 'Lehrbub'
WHEN 3 THEN 'Könner'
WHEN 4 THEN 'Halbgott'
ELSE 'Sitzenbleiber'
END
FROM Schueler ORDER BY 2
(oft 'm' ==> 'Herr', 'w' ==> 'Frau')
Fallunterscheidung: CASE (2)
●
Variante 2: Test mit Bedingungen
(werden von oben nach unten durchgeprüft)
SELECT Vorname, Nachname,
CASE
WHEN Note < 2.0 THEN 'Super'
WHEN Note >= 4.5 THEN 'War nix'
ELSE 'Geht so'
END
FROM Schueler ORDER BY 2
Ergebnisse speichern: INTO
(nicht in MySQL!)
SELECT * INTO SchuelerBackup
FROM Schueler
Macht eine Kopie SchuelerBackup
der Tabelle Schueler.
SELECT DISTINCT Klasse
INTO Klassenliste
FROM Schueler
Legt eine neue Tabelle Klassenliste an
(mit einer einzigen Spalte Klasse)
und befüllt sie mit dem Ergebnis des SELECT.
Ergebnisse kombinieren: UNION
SELECT
FROM
UNION
SELECT
FROM
S.Vorname, S.Nachname, 'Student'
Schueler AS S
L.Vorname, L.Nachname, 'Professor'
Lehrer AS L
Vereinigt die Ergebnis-Zeilen mehrerer SELECT
(mehrfache, gleiche Zeilen in der Vereinigung
werden nur einmal ausgegeben)
Spaltenanzahl & Spaltentyp aller SELECT
müssen gleich sein!
Ergebnisse kombinieren: Andere
Analog:
UNION ALL
Wie UNION, aber doppelte bleiben erhalten
INTERSECT
nur die Zeilen, die in beiden Ergebnissen vorkommen
MINUS (oder EXCEPT)
nur die Zeilen, die im ersten
und nicht im zweiten Ergebnis vorkommen
Achtung:
MySQL kennt INTERSECT und MINUS nicht!
Zeilen auswählen: WHERE (1)
SELECT * FROM Schueler
WHERE Klasse = 'AIK2'
Nur die Zeilen, bei denen Klasse den Wert “AIK2” hat.
WHERE kommt nach dem FROM
und vor dem ORDER BY.
Hinweise zu WHERE:
●
Die Vergleiche sind
= (nicht == !)
<> (bei manchen DB auch !=)
<, <=, >, >=
Zeilen auswählen: WHERE (2)
●
●
●
●
Zahlen-Konstanten mit . und ohne Anführungszeichen,
Texte in einfachen oder doppelten Anführungszeichen.
Datums- und Zeitwerte werden richtig verglichen.
Datums-Konstanten in einfachen Anführungszeichen,
Schreibweise je nach DB und Spracheinstellung
('yyyy-mm-dd' oder 'dd.mm.yyyy').
Mehrere Bedingungen:
AND, OR, XOR, NOT, ( ) für Vorrang
... WHERE Klasse = 'AIK2'
AND GebDat < '1994-01-01' ...
Zeilen auswählen: WHERE (3)
●
Statt Spaltennamen und Konstanten können
in Vergleichen auch Funktionen verwendet werden.
Verfügbare Funktionen sind aber DB-abhängig.
... WHERE LENGTH(Nachname) > 10 ...
... WHERE ROUND(Note, 0) = 5 ...
... WHERE MONTH(GebTag) = MONTH(NOW()) ...
Prüfung auf Bereiche: BETWEEN
... WHERE Note BETWEEN 3.5 AND 4.5
(oder auch ... xxx NOT BETWEEN ... )
(klappt auch für Datum und Zeit)
Achtung:
Laut Standard: Einschließlich der Randwerte
(nicht jede Datenbank hält sich daran...)
Suche von Texten: LIKE
... WHERE Klasse LIKE 'AIK_' ...
... WHERE Nachname LIKE 'Franz%' ...
... WHERE Klasse LIKE '%Bac%' ...
... WHERE Klasse NOT LIKE '%Bac%' ...
... WHERE Klasse LIKE 'InfBac[246]' ...
_ steht für genau ein beliebiges Zeichen
% steht für beliebig viele (auch keine) beliebige Zeichen
[...] steht für genau eines der angegebenen Zeichen
(in MySQL muss man das anders machen)
Prüfung auf “kein Wert”: IS NULL
... WHERE Note IS NULL ...
(oder auch ... WHERE Note IS NOT NULL ... )
Nur für Spalten,
in denen fehlende Werte (NULL) erlaubt sind:
Wählt die Zeilen aus,
in denen diese Spalte keinen Wert enthält.
Tücken von NULL-Werten
Achtung:
“Normale” Prüfungen liefern
für NULL-Werte immer “falsch”!
Sinnloses Beispiel:
SELECT Vorname, Nachname FROM Schueler
WHERE Note = 6.0 OR Note <> 6.0
liefert nicht alle Schüler, sondern nur die mit Note!
Für Schüler mit leerem Feld Note
sind beide Prüfungen falsch!
Prüfung mit Liste von Werten: IN
... WHERE Klasse
IN ( 'AIK2', 'PhyTA2', 'InfBac2' ) ...
Wählt die Zeilen aus, die in dieser Spalte
einen der angegebenen Werte haben.
Das kann eine fixe Liste oder
eine Unterabfrage mit einspaltigem Ergebnis sein:
... WHERE S.Klasse IN (
SELECT DISTINCT P.Klasse
FROM Stundenplan AS P
WHERE P.Lehrer = 'Kusche'
) ...
Prüfung auf “Treffer”: EXISTS
SELECT S.Vorname, S.Nachname
FROM Schueler AS S
WHERE EXISTS (
SELECT 1
(egal!)
FROM Stundenplan AS P
WHERE S.Klasse = P.Klasse
AND P.Lehrer = 'Schneider'
)
Wählt alle Zeilen aus, für die die Unterabfrage
ein nichtleeres Ergebnis (mindestens 1 Zeile) liefert.
Zeilenanzahl beschränken: LIMIT
SELECT * FROM Schueler LIMIT 3
Nur max. die ersten 3 Zeilen
SELECT Nachname, Note FROM Schueler
WHERE Klasse = 'AIK2'
ORDER BY Nachname LIMIT 10,5
5 Zeilen ab der 11. Zeile (z.B. für seitenweise Ausgabe)
Achtung:
●
Die Nummerierung beginnt bei 0, nicht 1 !
●
LIMIT kommt nach dem WHERE und dem ORDER BY
●
Manche Datenbanken kennen kein LIMIT, sondern SELECT TOP ... (anders)
Werte kombinieren (1)
Im SELECT kann eine Aggregatsfunktion stehen,
die die Werte einer Spalte aller Ergebnis-Zeilen
zusammenfasst:
SELECT COUNT(Nachname) FROM Schueler
WHERE Klasse = 'AIK2'
SELECT MAX(GebDat) FROM Schueler
SELECT AVG(Note) FROM Schueler
WHERE Klasse = 'AIK2'
SELECT SUM(Fehlstunden) FROM Schueler
==> Ergebnis: Eine Zeile mit einem Wert
Werte kombinieren (2)
Ein SELECT mit einer Zeile und einer Spalte Ergebnis
(meist: Aggregatsfunktion)
kann als Vergleichswert im WHERE verwendet werden:
SELECT Vorname, Nachname, Note
FROM Schueler
WHERE Klasse = 'AIK2'
AND Note < (
SELECT AVG(Note) FROM Schueler
WHERE Klasse = 'AIK2'
)
Zeilen zusammenfassen (1)
●
●
●
GROUP BY fasst mehrere Zeilen mit gleichem Wert
der angegebenen Spalte zu einer Zeile zusammen
Pro Gruppe wird eine Ergebnis-Zeile geliefert
Im SELECT dürfen nur angegeben werden:
- Spalten, nach denen gruppiert wurde
(die im GROUP BY stehen)
- Aggregatsfunktionen
●
●
Aggregatsfunktionen werden pro Gruppe gerechnet
Mit HAVING können die aggregierten Ergebniszeilen
mit einer Bedingung gefiltert werden
Zeilen zusammenfassen (2)
SELECT Klasse,
MIN(Note), AVG(Note), MAX(Note)
FROM Schueler
GROUP BY Klasse
ORDER BY 3 DESC
SELECT Klasse, Wochentag,
COUNT(*) AS Stundenanzahl
FROM Stundenplan
WHERE Klasse LIKE 'AIK_'
GROUP BY Klasse, Wochentag
HAVING COUNT(*) > 6
Zeilen zusammenfassen (3)
Im GROUP BY stehen oft auch Datumsfunktionen:
SELECT Klasse, MONTH(GebDat), COUNT(*)
FROM Schueler
GROUP BY Klasse, MONTH(GebDat)
ORDER BY 1, 2
SELECT YEAR(GebDat), MONTH(GebDat), COUNT(*)
FROM Schueler
GROUP BY YEAR(GebDat), MONTH(GebDat)
ORDER BY 1, 2
Tabellen verknüpfen: FROM (1)
●
●
●
Im FROM können mehrere Tabellen angegeben werden
Es werden zuerst alle möglichen Kombinationen
aus irgendeiner Zeile der ersten Tabelle
mit irgendeiner Zeile der zweiten Tabelle
gebildet (also m mal n viele Zeilen, “Kreuzprodukt”).
Dann werden die kombinierten (zusammengehängten)
Zeilen mit WHERE gefiltert.
(In der Praxis wird das optimiert!)
Tabellen verknüpfen: FROM (2)
●
Das WHERE sollte mindestens eine Bedingung haben,
die eine Spalte der linken Tabelle
mit einer Spalte der rechten Tabelle vergleicht
(meist mit = )
SELECT DISTINCT S.Nachname, P.Lehrer
FROM Schueler AS S,
Stundenplan AS P
WHERE S.Klasse = P.Klasse
AND DayOfWeek(S.GebTag) = P.Wochentag
ORDER BY 1
Tabellen verknüpfen: FROM (3)
Man kann auch eine Tabelle mit sich selbst verknüpfen
(“Self Join”):
SELECT S1.GebDat, S1.Nachname, S2.Nachname
FROM Schueler AS S1, Schueler AS S2
WHERE S1.Klasse = S2.Klasse
AND S1.GebTag = S2.GebTag
AND S1.Nachname < S2.Nachname
ORDER BY 1
Tabellen verknüpfen: FROM (4)
Auch das Gruppieren funktioniert:
SELECT DISTINCT P.Fach, P.Lehrer,
MIN(S.GebDat), MAX(S.GebDat)
FROM Schueler AS S,
Stundenplan AS P
WHERE S.Klasse = P.Klasse
GROUP BY P.Fach, P.Lehrer
ORDER BY P.Fach, P.Lehrer
(die Abfrage ist so nicht wirklich clever...)
Tabellen verknüpfen: JOIN (1)
Die üblichere Schreibweise für 2 Tabellen ist JOIN:
FROM Tabelle1
INNER JOIN Tabelle2
ON Spalte1 = Spalte2 ...
WHERE ...
●
INNER kann man ev. weglassen, ist oft Default
●
Mit mehreren JOIN ... ON auch für mehrere Tabellen
●
Die “Verknüpfungsbedingung”
zwischen den Tabellen gehört ins ON,
andere Bedingungen (auf nur 1 Tabelle) ins WHERE
Tabellen verknüpfen: JOIN (2)
SELECT DISTINCT S.Nachname, P.Lehrer
FROM Schueler AS S
INNER JOIN Stundenplan AS P
ON S.Klasse = P.Klasse
WHERE DayOfWeek(S.GebTag) = P.Wochentag
ORDER BY 1
Im ON sollte als erstes
eine Fremdschlüssel-Spalte einer Tabelle
gleich (=)
der Primärschlüssel-Spalte der anderen Tabelle
gesetzt werden (siehe später!)
Tabellen verknüpfen: JOIN (3)
Neben INNER JOIN gibt es auch noch
LEFT JOIN: Alle Zeilen der linken Tabelle, auch wenn
die rechte Tabelle keinen passenden Eintrag hat
oder die JOIN-Spalte links NULL enthält
RIGHT JOIN: Alle Zeilen der rechten Tabelle, auch wenn
die linke Tabelle keinen passenden Eintrag hat oder...
FULL JOIN: Alle Zeilen beider Tabellen,
Zeilen mit erfüllten Bedingung werden kombiniert
(nicht in MySQL!)
Gibt es in einer der Tabellen keine passende Zeile,
werden stattdessen NULL-Werte verwendet.
Tabellen verknüpfen: JOIN (4)
SELECT DISTINCT L.Nachname, P.Klasse
FROM Lehrer AS L
LEFT JOIN Stundenplan AS P
ON L.Nachname = P.Lehrer
ORDER BY 1, 2
(liefert auch je eine Zeile für diejenigen Lehrer,
die in keiner Klasse unterrichten,
die Spalte Klasse bleibt dann leer)
Unterabfragen (1)
... sind ein SELECT (in ( ) ) innerhalb eines SELECT.
Inneres SELECT wird zuerst ausgerechnet.
3 Fälle:
●
●
●
Unter-SELECT liefert 1 Zeile mit 1 Spalte
(z.B. Aggregatsfunktion wie AVG, Bsp. siehe dort!)
==> Verwendung als Wert in einem Vergleich usw.
Unter-SELECT liefert mehrere Zeilen mit 1 Spalte
==> Verwendung als Liste im WHERE ... IN ... (Bsp. dort)
Unter-SELECT liefert bel. viele Zeilen und Spalten
==> Verwendung als Tabelle im FROM oder JOIN
Unterabfragen (2)
SELECT S.Nachname, S.Klasse, T.Stundenanz
FROM Schueler AS S, (
SELECT P.Klasse, COUNT(*) AS Stundenanz
FROM Stundenplan AS P
WHERE P.Wochentag = DayOfWeek(Now())
GROUP BY P.Klasse
) AS T
WHERE S.Klasse = T.Klasse
ORDER BY 1
Views (1)
Views sind “virtuelle” bzw. “berechnete” Tabellen:
●
●
●
Views sind SELECT-Befehle,
die fix mit einem Namen
in der DB gespeichert werden
(als Befehl, ohne das SELECT auszurechnen!).
Views-Namen können
wie Tabellen-Namen verwendet werden.
Bei jeder Verwendung eines View
wird das SELECT frisch ausgerechnet
und das Ergebnis wie eine Tabelle verwendet.
(d.h. die Daten eines View werden nicht fertig in der DB gespeichert!)
Views (2)
Anlegen eines View:
CREATE VIEW LehrerlisteV
AS SELECT DISTINCT Klasse, Lehrer
FROM Stundenplan
==> LehrerlisteV verhält sich wie eine Tabelle
mit 2 Spalten: Klasse und Lehrer
(welche Klasse hat welche Lehrer?)
Ein View kann auch mehrere Tabellen kombinieren
(z.B. mit JOIN) und sogar andere Views enthalten.
Views (3)
Verwendung von Views:
Views machen SELECT's einfacher und strukturierter
==> Leichter lesbar!
SELECT S.Nachname, S.Vorname, S.Klasse
FROM Schueler AS S, LehrerlisteV AS L
WHERE L.Lehrer = 'Kusche'
AND L.Klasse = S.Klasse
ORDER BY 3, 1
Der erste Schritt beim Entwurf
einer Datenbank-Anwendung:
Die Strukturierung
der Daten
Spalten-Typen
INT, DOUBLE, BOOL, ENUM, ...
DECIMAL = Fixkommazahlen ohne Rundungsfehler:
Mit Dezimalziffern statt binär gespeichert / gerechnet
CHAR = Strings fixer Länge, rechts mit ' ' aufgefüllt:
Etwas schneller als VARCHAR, aber braucht mehr Platz
VARCHAR = Strings variabler Länge, mit Maximal-Länge:
Platzsparender, aber minimal langsamer als CHAR
BINARY = beliebige Bytes fixer Länge
DATE, DATETIME, ...
BLOB = “Binary Large OBject” (> 64 KB): Dokumente, Grafiken,
unstrukturierte Messdaten, Verschlüsseltes, usw. .
Wird separat gespeichert ==> Langsamer als VARCHAR usw.!
TEXT = ähnlich BLOB für große Texte
Spalten-Eigenschaften (1)
●
●
●
●
NULL oder NOT NULL:
Darf eine Spalte NULL-Werte enthalten
(in manchen Zeilen leer bleiben)?
UNIQUE:
Müssen die Werte der Spalte eindeutig sein
oder sind doppelte Werte erlaubt? (==> Fehler beim Einfügen!)
AUTO_INCREMENT:
Die Spalte wird automatisch nummeriert:
Jeder neue Zeile bekommt einen um 1 höheren Wert.
DEFAULT:
Wird beim INSERT kein Wert für die Spalte gesetzt,
so bekommt sie den angegebenen Standard-Wert.
Spalten-Eigenschaften (2)
Bei CHAR, VARCHAR, TEXT, ...:
●
Zeichensatz:
Latin-1, Unicode, ...
●
Sortierreihenfolge:
Binär (nach ASCII- bzw. Unicode-Wert) oder
Länderspezifisch (Umlaute korrekt einsortiert)?
Groß-/Kleinschreibung ignorieren oder beachten
(Kleinbuchstaben hinter Großbuchstaben)?
Spalten-Constraints
Man kann für die Werte einer Spalte beliebige
Bedingungen bzw. Einschränkungen festlegen.
Beispiele:
●
CHECK ((Note >= 1.0) AND (Note <= 6.0))
●
CHECK (Land IN ('De', 'At', 'Ch'))
==> Zeilen mit Werten,
die der Bedingung nicht entsprechen
können gar nicht eingefügt werden!
Spalten mit Index
Ein Index (= Suchverzeichnis) über eine Spalte hilft ...
●
●
Zeilen mit bestimmten Werten in dieser Spalte
schneller zu finden
(ohne Index: Alle Zeilen der Tabelle durchsuchen!)
Zeilen der Tabelle nach dieser Spalte
schneller sortiert auszugeben (gleich sortiert lesen)
(ohne Index: Nachträglich sortieren!)
Aber ein Index kostet ...
●
●
Viel Platz (oft: Alle Werte doppelt in Index & Tabelle)
Viel Aufwand (bei jedem Einfügen / Ändern / Löschen:
Index muss auch geändert werden!)
Primärschlüssel-Spalte
Primärschlüssel
= Eindeutige Identifizierung jeder Zeile
(nie zwei Zeilen mit gleichem Primärschlüssel!)
= Internes Such- und Ordnungskriterium
Immer NOT NULL und UNIQUE !
Meist zugleich Index
Meist ein “Kunstwert”, oft AUTO_INCREMENT:
Matrikelnummer, Artikelnummer, Vertragsnummer, ...
Primärschlüssel als Kombination mehrerer Spalten:
Bei vielen DB möglich, aber nur selten sinnvoll (Beispiel kommt später!)
==> Oft: Lieber eine zusätzliche Spalte mit neuem Kunstwert erfinden!
Fremdschlüssel-Spalte (1)
Fremdschlüssel
= Primärschlüssel einer anderen Tabelle
= Querverbindung / Verknüpfung zwischen Tabellen
(meist für =-Bedingungen in JOINs)
Ein Fremdschlüssel ist ein Spalten-Constraint
==> In die Spalte können nur Werte eingefügt werden, die
in der Ziel-Tabelle als Primärschlüsselwert vorkommen!
(und ev. NULL)
Das ist das “C” (“Konsistenz”) in “ACID”:
Die Fremdschlüssel-Beziehungen sind immer konsistent:
“Kein Fremdschlüssel-Wert ohne passenden Primärschlüssel-Wert!”
Fremdschlüssel-Spalte (2)
DB macht automatisch umgekehrte Konsistenzprüfung:
Beim Löschen / Ändern einer Zeile der Ziel-Tabelle:
Wenn der betroffene Primärschlüssel-Wert
noch irgendwo als Fremdschlüssel-Wert vorkommt
==> Entweder Löschen / Ändern überhaupt verhindern
==> Oder in allen verknüpften Tabellen die
betroffenen Zeilen automatisch auch ändern / löschen
==> Oder in allen verknüpften Tabellen automatisch den
betreffenden Fremdschlüssel-Wert auf NULL setzen
(deshalb sind Fremdschlüssel-Spalten automatisch auch Index-Spalten)
Fremdschlüssel-Spalte (3)
Beispiele:
Artikelnummer = Primärschlüssel in Artikel-Tabelle
= Fremdschlüssel in Bestellungen-Tabelle
Postleitzahl = Primärschlüssel in PLZ-Verzeichnis
= Fremdschlüssel in Adress- bzw. Kunden-Tabelle
Kundennummer = Primärschlüssel in Kunden-Tabelle
= Fremdschlüssel in Bestellungen-Tabelle
In seltenen Fällen Selbstbezug: “Rekursiver” Fremdschlüssel
= Primärschlüssel der eigenen Tabelle
Beispiel: Tabelle der Abteilungen einer Firma (Schlüssel Abteilung)
Spalte “übergeordnete Abteilung” muss gültige Abteilung sein!
Tabellen-Design (1)
In der Theorie:
1. / 2. / 3. Normalform
In der Praxis:
“Redundanzen vermeiden”
Redundante Informationen
= doppelt gespeicherte Informationen
= Informationen, die sowieso schon
aus anderen Informationen folgen
(z.B. aus 'Datum' ergibt sich 'Wochentag',
aus 'Klasse' ergibt sich 'Klassenlehrer')
Tabellen-Design (2)
Probleme dadurch:
●
Platzbedarf
●
Änderungsaufwand
(Kunde zieht um ==> Adresse an x Stellen ändern?)
●
Inkonsistenzen, Probleme beim Suchen
(Plz 88316 ==> einmal “Isny”, einmal “Isny i.A.”, einmal “Isny / Allgäu”)
Ziel meist:
●
Lieber mehrere, aber kleinere Tabellen
●
Nicht zu viele Indices auf einer Tabelle
Tabellen-Design (3)
1. Schritt:
Nicht mehrere Informationen
in eine einzige Spalte packen!
Schlecht: Je eine einzige Spalte für
●
Anrede, Titel, Vorname, Name
●
Komplette Adresse (Straße, Nummer, PLZ, Ort, Land)
●
Mehrere Noten (als Text mit ' ' verbunden)
Tabellen-Design (4)
2. Schritt:
Dieselbe Info nicht doppelt
in mehreren Tabellen
Schlecht: Komplette Kundendaten
in Verträgen, Schadensfällen, Rechnungen, ...
==> Eine separate Kunden-Tabelle,
sonst überall nur Kundennummer
Schlecht: Komplette Lehrer-Daten (Name, Adr, Tel, ...)
in Stundenplan, Notenliste, Terminkalender, ...
==> Eine Lehrer-Tabelle mit Lehrer-Kurzzeichen als Schlüssel,
in anderen Tabellen überall nur Kurzzeichen
Tabellen-Design (5)
3. Schritt:
Dieselbe Info nicht mehrmals
in einer Tabelle
Schlecht: Fächer und Lehrer bei jedem Schüler,
steht x Mal gleich in der Schüler-Tabelle
==> Fächer und Lehrer woanders pro Klasse speichern,
bei jedem Schüler nur die Klasse eintragen
Schlecht: Postleitzahl, Bundesland und Ort
stehen wiederholt bei jeder Adresse
==> Adressen enthalten nur die Postleitzahl,
eigene PLZ-Tabelle mit Ort und Bundesland
Tabellen-Design (6)
Tipp dazu:
Prüfen: Hat eine Tabelle Spalten, ...
●
●
deren Wert durch etwas anderes als den Primärschlüssel
schon eindeutig festgelegt ist?
die nur voneinander,
aber nicht vom Primärschlüssel abhängig sind?
==> Zusammengehörige Spalten
in eigene Tabelle auslagern!
Tabellen-Design (7)
Beispiele:
●
'Ort' hängt nur von 'Plz' ab (ist durch 'Plz' festgelegt),
nicht von 'Kunden-Nr' bzw. 'Matrikel-Nr'
==> 'Ort' gehört nicht in Kunden- oder Schüler-Tabelle,
sondern in eigene Tabelle mit Primärschlüssel 'Plz'!
●
'Fach', 'Lehrer' und 'Klasse' sind
nur voneinander abhängig, nicht von Schüler
==> Nicht alle drei bei jedem Schüler speichern,
sondern nur die Klasse.
==> Eigene Tabelle mit 'Fach', 'Lehrer' und 'Klasse',
Primärschlüssel ist 'Fach' + 'Klasse'.
Und wenn unser Design fertig ist...
... legen wir die Tabellen
mit der grafischen Administrations-Oberfläche
der Datenbank an.
Das geht alles auch mit SQL-Befehlen
(siehe SQL-Übersicht!),
aber das ist für uns zu aufwändig.
Bisher können wir nur Daten lesen,
aber wir müssen auch...
Daten einfügen /
ändern / löschen
INSERT einzelner Zeilen
INSERT INTO tabelle (spaltenliste)
VALUES (werteliste)
Beispiel:
INSERT INTO Lehrer
(Vorname, Nachname, TelNr)
VALUES ("Klaus", "Kusche", 36)
Für Null-, Default- und Autoincrement-Spalten
muss man keine Werte angeben, sonst alle.
INSERT + SELECT (1)
INSERT INTO tabelle (spaltenliste)
SELECT ...
●
●
Das SELECT-Ergebnis muss so viele Spalten haben
wie in spaltenliste angegeben,
und der Typ muss zusammenpassen
(Zuordnung von links nach rechts).
Es werden so viele Zeilen eingefügt,
wie das SELECT Zeilen liefert.
INSERT + SELECT (2)
Beispiel:
INSERT INTO Schueler
(Vorname, Nachname, Jahrgang, Klasse, ... )
SELECT Vorname, Nachname, 2013, "AIK3", ...
FROM Schueler
WHERE Jahrgang = 2012
AND Klasse = "AIK2"
UPDATE (1)
UPDATE tabelle
SET spalte = neuer_wert
WHERE zeilenauswahl
●
●
●
In allen Zeilen der Tabelle tabelle,
in denen das WHERE zutrifft,
wird in der Spalte spalte
der Wert neuer_wert gespeichert.
Mit spalte1 = neuer_wert1, spalte2 = neuer_wert2, ...
können mehrere Spalten der gewählten Zeilen
auf einmal geändert werden.
Nicht angegebene Spalten bleiben unverändert.
UPDATE (2)
●
neuer_wert kann eine Konstante
oder eine Rechnung oder ein Sub-SELECT sein
Beispiele:
UPDATE Schueler SET Note = 6
(Kein WHERE ==> trägt in allen Zeilen 6 ein!)
UPDATE Schueler SET Note = Note - 0.5
WHERE Note > 3
(mach alle Noten über 3 um eine halbe Note besser)
UPDATE Schueler
SET Jahrgang = 2013, Klasse = "AIK3"
WHERE Jahrgang = 2012 AND Klasse = "AIK2"
DELETE
DELETE FROM tabelle
WHERE zeilenauswahl
●
●
Löscht alle Zeilen aus der Tabelle tabelle,
für die das WHERE zutrifft.
Es gibt ein UPDATE und ein DELETE zusammen mit JOIN,
aber das lassen wir aus...
Beispiele:
DELETE FROM Lehrer
(löscht alle Zeilen ==> leere Tabelle bleibt übrig)
DELETE FROM Schueler WHERE Note >= 4.5
Transaktionen in MySQL
●
MySQL konnte jahrelang keine Transaktionen
●
Auch heute noch ist standardmäßig eingestellt:
AUTOCOMMIT = 1
Bedeutung:
Nach jedem SQL-Befehl automatisch sofort COMMIT
==> Jeder Befehl für sich ist eine eigene Transaktion.
Vorteile:
●
Max. 3-5 mal schneller als mit Transaktionen
●
Braucht deutlich weniger RAM & Platte
Nachteile von AUTOCOMMIT
●
Nicht parallelitätsfest:
Gleichzeitig laufende Transaktionen sehen
●
●
●
●
“Zwischenstand” zwischen
zusammengehörigen Befehlen
Ev. sogar “halbe” Daten eines großen Befehls
Keine ROLLBACK-Möglichkeit,
z.B. bei Erkennen eines Problems.
Weniger ausfallsicher, z.B. bei Stromausfall
in zusammengehörenden oder großen Befehlen.
Klassisches Beispiel: Konto-Umbuchung
Transaktionen verwenden (1)
●
Variante 1 (nur MySQL): SET AUTOCOMMIT = 0
==> Automatisch neues START TRANSACTION
nach jedem COMMIT oder ROLLBACK
●
Variante 2: Expliziter Befehl START TRANSACTION
(oder in MySQL, nicht Standard: BEGIN)
==> Alle Befehle zwischen dem START TRANSACTION
und dem nächsten COMMIT oder ROLLBACK
gehören zu einer einzigen
Transaktion.
Transaktionen verwenden (2)
Was gehört in eine Transaktion?
Alle aufeinanderfolgenden Befehle,
●
●
die logisch zusammengehören
(zu einer Umbuchung oder Änderung,
zum Eintragen neuer Daten in mehreren Tabellen, ...)
die entweder ganz oder gar nicht
ausgeführt werden sollen.
... und nicht mehr!
(wegen hohem Overhead, Blockieren von Tabellen, ...)
COMMIT & ROLLBACK
COMMIT:
Alle Befehle der aktuellen Transaktion
●
werden endgültig in der Datenbank gespeichert
●
werden erst jetzt für andere Befehle sichtbar
oder
ROLLBACK:
Alle Befehle der aktuellen Transaktion
●
werden spurlos rückgängig gemacht
(passiert automatisch bei Fehlern & Ausfällen)
Herunterladen