SQL-Einführung

Werbung
SQL-Einführung
Skript zur grundlegenden Orientierung innerhalb des Datenbestandes mittels SQL. Unterstrichene
Begriffe können für weitere Details in Wikipedia eingegeben werden (www.wikipedia.at).
Einführung Datenbanken
Grundsätzlich dient jedes Datenbanksystem (DBS) dazu, große Datenmengen effizient,
widerspruchsfrei und dauerhaft zu speichern.
Im Zuge der Weiterentwicklung der EDV haben sich aber auch Datenbanken über die Jahre verändert.
Waren früher viele hierarchische oder proprietäre Systeme (also diverse Eigenentwicklungen, vor
allem auf Großrechnerebene) vorrangig, so haben sich bereits in den 70ern sogenannte relationale
Datenbanksysteme durchgesetzt. Relationale Datenbanken bestehen grundsätzlich aus Tabellen,
welche durch Beziehungen miteinander in Verbindung stehen. Die Erstellung eines solchen
Tabellenkonzeptes nennt man Datenmodellierung, das Ergebnis ein Datenbankmodell.
Einführung SQL
SQL bedeutet Structured Query Language und wurde mit der Entstehung von relationalen
Datenbanksystemen (RDBMS) entwickelt. Es handelt sich dabei um einen Abfragestandard für
Tabelleninhalte – wobei leider jede Datenbankumgebung im Laufe der Jahre ihren eigenen „Dialekt“
entwickelt hat. Es gibt also viele Gemeinsamkeiten aber eben auch einige Unterschiede, die vor allem
im Detail zu finden sind. Im Folgenden wird speziell auf die MSSQL-Syntax eingegangen, wobei
Unterschiede zu anderen Datenbanksystemen bei Bedarf angeführt werden.
Beispieldaten
Um die Erläuterungen in diesem Skript besser verständlich zu machen, soll nachfolgendes einfaches
Datenbankschema dienen:
Titel
Id
Name
Person
Id
Vorname
Nachname
Ref_Titel_Id
Ref_Adresse_Id
Geburtsdatum
Adresse
Id
Strasse
Hausnummer
Ref_Ort_Id
Ort
Plz
Name
Die Basistabelle beinhaltet Personen. Diese Personen haben unter Umständen einen Titel. Damit
dieser nicht hundertfach zu jeder Person erfasst werden muss, wird der Text in eine eigene Tabelle
ausgelagert und nur die Referenz zum jeweiligen Titel gespeichert. Ebenso verhält es sich mit den
Adressen. Da mehrere Personen an einer Adresse wohnen können, werden diese Anschriften nur ein
mal gespeichert und über die Referenzen eingebunden. Innerhalb der Adressen sind wiederum die
Orte mehrfach vorhanden und daher ebenfalls ausgelagert.
Diese Auslagerung von Daten und deren Verbindung durch Relationen dient dazu Redundanzen
(mehrfach vorkommende Daten selben Inhalts) zu verhindern. Man nennt dies Normalisierung.
Seite 1 von 7
Grundsätzlicher Aufbau eines SQL-Statements
SELECT feld(er)
FROM tabelle [ ,...tabelle ]
[ [ INNER | LEFT | RIGHT | OUTER ] JOIN ] tabelle ON (tabelle1.feld = tabelle2.feld)
WHERE bedingung(en)
GROUP BY gruppierfeld [ ,...gruppierfeld ]
ORDER BY sortierfeld [ ,...sortierfeld ] ;
SELECT
Jede Abfrage beginnt mit den Schlüsselwort SELECT. Mit SELECT * kann man alle Spalten einer
(oder mehrerer) Tabellen auslesen. Dies ist aber aus Performancegründen bei großen Datenmengen
nicht zu empfehlen. Besser ist die gezielte Angabe der gewünschten Spalten.
FROM
Um dem Datenbanksystem mitzuteilen, in welcher Tabelle die im SELECT angegebenen Felder zu
finden sind, gibt es das Schlüsselwort FROM. Hier wird eine Tabelle angegeben.
Beispiel:
SELECT Vorname, Nachname
FROM Person;
JOIN
Wenn die gewünschten Daten über mehrere Tabellen verteilt sind, so müssen diese entsprechend
miteinander verknüpft werden. Dazu dient das JOIN-Schlüsselwort. Zu jedem JOIN müssen die
Verknüpfungsparameter angegeben werden (ON ...). Es können auch mehrere Tabellen verknüpft
werden. Hierbei können verschiedene Arten der Verknüpfung angegeben werden:
INNER JOIN
Liefert nur Datensätze, die in beiden Tabellen vorkommen.
SELECT Titel.Name, Person.Vorname, Person.Nachname
FROM Person
INNER JOIN Titel ON (Titel.Id = Person.Ref_Titel_Id);
Liefert nur Datensätze aus Personen, die auch einen Titel haben.
Seite 2 von 7
OUTER JOIN
Liefert alle Datensätze aus beiden Tabellen. Leere Felder werden hierbei mit NULL befüllt.
SELECT Titel.Name, Person.Vorname, Person.Nachname
FROM Person
OUTER JOIN Titel ON (Titel.Id = Person.Ref_Titel_Id);
Liefert alle verknüpften Datensätze aus Personen und Titeln! Es kann Personen geben, die
keinen Titel haben – aber auch Titel ohne Vor- und Nachnamen!
LEFT JOIN
Aus der auf der linken Seite angeführten Tabelle werden alle Datensätze selektiert.
SELECT Titel.Name, Person.Vorname, Person.Nachname
FROM Person
LEFT JOIN Titel ON (Titel.Id = Person.Ref_Titel_Id);
Liefert alle Personen (= „linke Tabelle“) – manche davon haben jedoch keinen Titel.
RIGHT JOIN
Aus der auf der rechten Seite angeführten Tabelle werden alle Datensätze selektiert.
SELECT Titel.Name, Person.Vorname, Person.Nachname
FROM Person
RIGHT JOIN Titel ON (Titel.Id = Person.Ref_Titel_Id);
Liefert alle Titel (= „rechte Tabelle“) – manche davon haben jedoch keinen Vor- oder
Nachnamen.
Ein Komplettbeispiel für unsere Beispieldatenbank würde demnach so aussehen:
SELECT t.Name, p.Vorname, p.Nachname, a.Strasse, a.Hausnummer, o.Plz, o.Name
FROM Person p
LEFT JOIN Titel t ON (t.Id = p.Ref_Titel_Id)
LEFT JOIN Adresse a ON (a.Id = p.Ref_Adresse_Id)
LEFT JOIN Ort o ON (o.PLZ = a.Ref_Ort_Id) ;
Dieses Statement liefert alle Personen mit ihrem Titel, der Adresse und dem zugehörigen Ort.
Sind Felder einer oder mehrerer verknüpften Tabellen leer, werden diese mit NULL ausgegeben.
Seite 3 von 7
WHERE
Über das Schlüsselwort WHERE werden Daten genauer eingeschränkt und gefiltert. Dabei können
auch mehrere Bedingungen kombiniert werden. Es gelten hierbei die Klammernregeln. In einigen
Datenbankensystemen ist der Feldtyp nicht so ausschlaggebend und man kann grundsätzlich jede
Bedingung in Hochkomma setzen. Bei MSSQL ist jedoch der Feldtyp relevant und man muss diesen
auch in den Bedingungen berücksichtigen:
Zahlen werden ohne Hochkomma angegeben. Bei Dezimalzahlen ist ein Hochkomma jedoch zulässig
(damit das Komma nicht als Feldseparator interpretiert wird).
Text ist immer in Hochkomma zu setzen.
Datumswerte sind besonders zu behandeln. Hier ist auf das Datenformat der Datenbank zu achten!
Bedingungsoperatoren:
=, <, >, <=, >=, LIKE, IN, NOT IN, BETWEEN
SELECT t.Name, p.Vorname, p.Nachname, a.Strasse, a.Hausnummer, o.Plz, o.Name
FROM Person p
LEFT JOIN Titel t ON (t.Id = p.Ref_Titel_Id)
LEFT JOIN Adresse a ON (a.Id = p.Ref_Adresse_Id)
LEFT JOIN Ort o ON (o.PLZ = a.Ref_Ort_Id)
WHERE (t.Name = ‘Ing.’ OR t.Name = ‘Dr.’)
AND (o.plz = 1230)
AND (p.Nachname LIKE ‘Hof%’ OR p.Nachname LIKE ‘Höf%’)
AND p.Geburtsdatum >= '20.11.1990’;
Liefert alle Personen, die entweder den Titel “Ing.“ oder „Dr.“ tragen, in 1230 wohnen, deren
Nachname mit „Hof...“ oder „Höf...“ beginnt und die am oder nach dem 20.11.1990 geboren wurden.
Achtung! Gibt man bei Datumsfeldern keine Uhrzeit mit an, wird vom System 00:00 Uhr angenommen.
Dies kann zu ungewüschten Effekten führen, wenn man zB genau auf ein bestimmtes Datum abfragen
möchte!
SELECT Vorname, Nachname
FROM Person
WHERE Geburtsdatum = '20.11.1990’;
Diese Abfrage liefert wahrscheinlich keine Ergebnismenge – es sei denn, eine Person hat tatsächlich
genau um 00:00 Uhr dieses Tages Geburtstag!
Seite 4 von 7
Hier empfiehlt sich folgende Abfrage:
SELECT Vorname, Nachname
FROM Person
WHERE Geburtsdatum >= '20.11.1990’
AND Geburtsdatum < '21.11.1990’;
GROUP BY
Gibt es mehrere Einträge zu bestimmten Suchkriterien, kann man diese nach Bedarf auch gruppiert
ausgeben lassen. Es werden dann Spalten mit gleichem Inhalt gemäß der Group-By-Angaben
zusammengefasst. Andere Spalten können mithilfe von Aggregatfunktionen kalkuliert werden (siehe
dazu Aggregatfunktionen weiter unten).
Wichtig hierbei ist, dass sämtliche Spalten, nach denen gruppiert werden soll auch in der Feldliste des
SELECTs stehen müssen!
SELECT Nachname, COUNT(Vorname)
FROM Person
GROUP BY Nachname
Liefert pro Nachnamen eine Zeile – in der zweiten Spalte steht dann jeweils die Anzahl der
Datensätze zu diesem Nachnamen.
ORDER BY
Um die Ausgabe entsprechend zu sortieren, gibt es die Order-By-Klausel. Hier werden wie auch
schon in der Select-Liste die Feldnamen getrennt durch Beistriche angeführt. Zustätzlich kann hier pro
Feld der Zusatz ASC (Ascending = aufsteigend) oder DESC (Descending = absteigend) angegeben
werden.
SELECT t.Name, p.Vorname, p.Nachname, a.Strasse, a.Hausnummer, o.Plz, o.Name
FROM Person p
LEFT JOIN Titel t ON (t.Id = p.Ref_Titel_Id)
LEFT JOIN Adresse a ON (a.Id = p.Ref_Adresse_Id)
LEFT JOIN Ort o ON (o.PLZ = a.Ref_Ort_Id)
WHERE (t.Name = ‘Ing.’ OR t.Name = ‘Dr.’)
AND (o.plz = 1230)
AND (p.Nachname LIKE ‘Hof%’ OR p.Nachname LIKE ‘Höf%’)
AND p.Geburtsdatum >= '20.11.1990’
ORDER BY p.Nachname ASC, p.Vorname DESC;
Seite 5 von 7
Selbe Ergebnismenge wie im WHERE-Beispiel – nun aber nach Nachnamen sortiert. Innerhalb von
gleichen Nachnamen werden die Vornamen absteigend ausgegeben (also beginnend mit „Z...“).
Aggregatfunktionen
TOP xx
Ausgabe auf xx Zeilen einschränken
AVG(Ausdruck)
Berechnet den Durchschnittswert einer Spalte, die durch den Ausdruck bestimmt wird
COUNT(Ausdruck)
Zählt die vom Ausdruck definierten Zeilen
COUNT(*)
Zählt alle Zeilen in der angegebenen Tabelle oder dem View
MIN(Ausdruck)
Findet den kleinsten Wert in der durch den Ausdruck angegebenen Spalte
MAX(Ausdruck)
Findet den größten Wert in der durch den Ausdruck angegebenen Spalte
SUM(Ausdruck)
Berechnet die Summe der durch den Ausdruck angegebenen Spaltenwerte
Beispiel:
SELECT TOP 100 COUNT(*), p.Vorname, p.Nachname, MIN(p.Geburtsdatum), AVG(o.Plz)
FROM Person p
LEFT JOIN Adresse a ON (a.Id = p.Ref_Adresse_Id)
LEFT JOIN Ort o ON (o.PLZ = a.Ref_Ort_Id)
GROUP BY p.Vorname, p.Nachname;
Listet maximal 100 Zeilen der gesamten Ergebnismenge. Die Ausgabe wird in Vorname + Nachname
gruppiert (also je eine Zeile für eine Vorname + Nachname-Kombination). Für jede Zeile wird die
Anzahl der Datensätze, das kleinste Geburtsdatum und der Durchschnitt der Postleitzahlen (wozu
auch immer) ausgegeben.
Seite 6 von 7
Eine typische Abfrage könnte also wie folgt aussehen:
Base-Select:
SELECT
Add-Select:
p.firstname AS 'Vorname',
p.lastname AS 'Nachname',
p.birthdate AS 'Geburtsdatum',
p.gender AS 'Geschlecht',
p.visit_date AS 'Erste Visite'
Base-From:
FROM WA_ADB_Patient p
INNER JOIN WC_ADB_CHPO c on (c.PatientID = p.PatientID)
Add-From:
Base-Where:
WHERE c.kst_id = '91631260'
AND c.storno = 0
Add-Where:
AND c.Visitendatum < '20.10.2008'
AND p.birthdate BETWEEN '01.01.1930' AND '31.12.2000'
AND p.lastname LIKE 'B%'
Order by:
ORDER BY p.lastname ASC
Seite 7 von 7
Herunterladen