SQL ist eine Datenbanksprache zur Definition von Datenstrukturen in relationalen Datenbanken sowie zum Bearbeiten (Einfügen, Verändern, Löschen) und Abfragen von darauf basierenden Datenbeständen.
Die Sprache basiert auf der relationalen Algebra, ihre Syntax ist relativ einfach aufgebaut und semantisch an die englische Umgangssprache angelehnt. Ein gemeinsames Gremium von ISO und IEC standardisiert die Sprache unter Mitwirkung nationaler Normungsgremien wie ANSI oder DIN. Fast alle gängigen Datenbanksysteme unterstützen SQL – allerdings in unterschiedlichem Umfang und leicht voneinander abweichenden „Dialekten“. Durch den Einsatz von SQL strebt man die Unabhängigkeit der Anwendungen vom eingesetzten Datenbankmanagementsystem an.
Die Bezeichnung SQL (offizielle Aussprache [ɛskjuːˈɛl], oft aber auch [ˈsiːkwəl] nach dem Vorgänger; auf deutsch auch häufig die deutsche Aussprache der Buchstaben) wird im allgemeinen Sprachgebrauch als Abkürzung für „Structured Query Language“ aufgefasst, obwohl sie laut Standard ein eigenständiger Name ist. Die Bezeichnung leitet sich von dem Vorgänger SEQUEL ([ˈsiːkwəl], Structured English Query Language) ab, welche mit Beteiligung von Edgar F. Codd (IBM) in den 1970er Jahren von Donald D. Chamberlin und Raymond F. Boyce entworfen wurde. SEQUEL wurde später in SQL umbenannt, weil SEQUEL ein eingetragenes Warenzeichen der Hawker Siddeley Aircraft Company ist.[1]
SQL-Befehle lassen sich in drei Kategorien unterteilen (Zuordnung nach der Theorie der Datenbanksprachen in Klammern):
Die Bezeichnung SQL bezieht sich auf das englische Wort „query“ (deutsch: „Abfrage“) . Mit Abfragen werden die in einer Datenbank gespeicherten Daten abgerufen, also dem Benutzer oder einer Anwendersoftware zur Verfügung gestellt.
Das Ergebnis einer Abfrage sieht wiederum aus wie eine Tabelle und kann oft auch wie eine Tabelle angezeigt, bearbeitet und weiterverwendet werden.
Die grundlegenden Befehle und Begriffe werden anhand des folgenden Beispiels erklärt:
ER-Diagramm: | ||||||||||||||||||||||||||||||||||||||||
---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
Relationen: |
|
|
|
|
SELECT * FROM Student;
listet alle Spalten und alle Zeilen der Tabelle Student auf.
Ergebnis:
MatrNr | Name |
---|---|
26120 | Fichte |
25403 | Jonas |
27103 | Fauler |
SELECT VorlNr, Titel FROM Vorlesung;
listet die Spalten VorlNr und Titel aller Zeilen der Tabelle Vorlesung auf.
Ergebnis:
VorlNr | Titel |
---|---|
5001 | ET |
5022 | IT |
5045 | DB |
SELECT DISTINCT MatrNr FROM hört;
listet nur unterschiedliche Einträge der Spalte MatrNr aus der Tabelle hört auf. Dies zeigt die Matrikelnummern aller Studenten, die mindestens eine Vorlesung hören, wobei mehrfach auftretende Matrikelnummern nur einmal ausgegeben werden.
Ergebnis:
MatrNr |
---|
25403 |
26120 |
SELECT MatrNr AS Matrikelnummer, Name FROM Student;
listet die Spalten MatrNr und Name aller Zeilen der Tabelle Student auf. MatrNr wird beim Anzeigeergebnis als Matrikelnummer aufgeführt.
Ergebnis:
Matrikelnummer | Name |
---|---|
26120 | Fichte |
25403 | Jonas |
27103 | Fauler |
SELECT VorlNr, Titel FROM Vorlesung WHERE Titel = 'ET';
listet VorlNr und Titel aller derjenigen Zeilen der Tabelle Vorlesung auf, deren Titel 'ET' ist.
Die solchermaßen strukturierte, häufig verwendete Anweisung wird nach den Anfangsbuchstaben auch als „SFW-Block“ bezeichnet.
Ergebnis:
VorlNr | Titel |
---|---|
5001 | ET |
SELECT Name FROM Student WHERE Name LIKE 'F%';
listet die Namen aller Studenten auf, deren Name mit F beginnt. (im Beispiel: Fichte und Fauler).
LIKE kann mit verschiedenen Platzhaltern belegt werden: _ steht für ein fehlendes Zeichen und % steht für eine beliebige Zeichenfolge. Bei der SQL-Version von Microsoft Access steht * für eine beliebige Zeichenfolge. So können mit der Abfrage auch Felder nach Inhalt durchsucht werden.
Ergebnis:
Name |
---|
Fichte |
Fauler |
SELECT Vorname, Name, StrasseNr, Plz, Ort FROM Student WHERE Plz = '20095' ORDER BY Name;
listet Vorname, Name, StrasseNr, Plz und Ort aller Studenten aus dem angegebenen Postleitzahlbereich, sortiert nach Name, auf.
SELECT Vorlesung.VorlNr, Vorlesung.Titel, Professor.PersNr, Professor.Name FROM Professor, Vorlesung WHERE Professor.PersNr = Vorlesung.PersNr;
Die Aufzählung hinter FROM legt die Datenquellen fest: an dieser Stelle können mit Hilfe sogenannter JOINs mehrere Tabellen über Schlüsselfelder miteinander verknüpft werden, so dass Daten aus verschiedenen Tabellen zusammengeführt und angezeigt werden.
Innerer natürlicher Verbund: Alle Datensätze aus den Tabellen Professor und Vorlesung, die den gleichen Wert im Feld PersNr haben. Professoren ohne Vorlesung und Vorlesungen ohne Professor werden damit nicht angezeigt.
Dies ist theoretisch äquivalent zu:
SELECT Vorlesung.VorlNr, Vorlesung.Titel, Professor.PersNr, Professor.Name FROM Professor INNER JOIN Vorlesung ON Professor.PersNr = Vorlesung.PersNr;
Vorsicht: Nicht alle Implementierungen verstehen die Schlüsselwörter „INNER“, „OUTER“ und „JOIN“.
Tabellen können auch ohne Verwendung von Schlüsselfeldern miteinander verknüpft werden:
SELECT Vorlesung.Titel, Professor.Name FROM Professor, Vorlesung WHERE Professor.PersNr = Vorlesung.PersNr;
Ergebnis:
Titel | Name |
---|---|
ET | Tesla |
IT | Wirth |
DB | Wirth |
SELECT Vorlesung.VorlNr, Vorlesung.Titel, Professor.PersNr, Professor.Name FROM Professor LEFT OUTER JOIN Vorlesung ON Professor.PersNr = Vorlesung.PersNr;
Äußerer linker Verbund: Alle Datensätze der Tabelle Professor und alle Datensätze aus beiden Tabellen, die den gleichen Wert im Feld PersNr haben. Professoren ohne Vorlesung sind enthalten, Vorlesungen ohne Professor sind nicht enthalten.
Die folgende Abfrage liefert nur diejenigen Datensätze, zu denen kein passender Datensatz im linken äußeren Verbund existiert (alle Professoren, die keine Vorlesungen halten):
SELECT Professor.PersNr, Professor.Name FROM Professor LEFT OUTER JOIN Vorlesung ON Professor.PersNr = Vorlesung.PersNr WHERE Vorlesung.PersNr IS NULL;
Das Gleiche mittels einer Unterabfrage:
SELECT a.PersNr, a.Name FROM Professor a WHERE NOT EXISTS (SELECT * FROM Vorlesung WHERE PersNr = a.PersNr);
SELECT COUNT(Vorlesung.PersNr) AS Anzahl, Professor.PersNr, Professor.Name FROM Professor LEFT OUTER JOIN Vorlesung ON Professor.PersNr = Vorlesung.PersNr GROUP BY Professor.Name, Professor.PersNr;
Äußerer linker Verbund und Gruppierung, Aggregation: Zählt die Anzahl der Vorlesungen pro Professor.
Bemerkung: COUNT(Professor.PersNr) oder COUNT(*) wären falsch (Nullwerte sollen nicht mitgezählt werden).
Zusammengefasst sind die wichtigsten Elemente einer SQL-SELECT-Abfrage wie folgt anzugeben:
SELECT [DISTINCT] Auswahlliste [AS Spaltenalias] FROM Quelle [ [AS] Tabellenalias] [WHERE Where-Klausel] [GROUP BY (Group-by-Attribut)+] [HAVING Having-Klausel] [ORDER BY (Sortierungsattribut [ASC|DESC])+];
Erläuterung:
Mengenoperatoren können auf mehrere SELECT-Abfragen angewandt werden, die gleich viele Attribute haben und bei denen die Datentypen der Attribute übereinstimmen:
Ein Grundsatz des Datenbankdesigns ist, dass in einer Datenbank keine Redundanzen auftreten sollen. Dies bedeutet, dass jede Information, also z. B. eine Adresse, nur genau einmal gespeichert wird.
In manchen Fällen ist die Performance einer Datenbank besser, wenn sie nicht (vollständig) normalisiert wird. In diesem Falle werden in der Praxis oft Redundanzen bewusst in Kauf genommen, um zeitaufwändige und komplexe Joins zu verkürzen und so die Geschwindigkeit der Abfragen zu erhöhen. Man spricht auch von einer Denormalisierung einer Datenbank. Wann (und ob überhaupt) eine Denormalisierung sinnvoll ist, ist umstritten und hängt von den Umständen ab.
Während die Informationen auf viele Tabellen verteilt werden müssen, um Redundanzen zu vermeiden, sind Schlüssel das Mittel, um diese verstreuten Informationen miteinander zu verknüpfen.
So hat in der Regel jeder Datensatz eine eindeutige Nummer oder ein anderes eindeutiges Feld, um ihn zu identifizieren. Diese Identifikationen werden als Schlüssel bezeichnet.
Wenn dieser Datensatz in anderen Zusammenhängen benötigt wird, wird lediglich sein Schlüssel angegeben. So werden bei der Erfassung von Vorlesungsteilnehmern nicht deren Namen und Adressen, sondern nur deren jeweilige Matrikelnummer erfasst, aus der sich alle weiteren Personalien ergeben.
So kann es sein, dass manche Datensätze nur aus Schlüsseln (meist Zahlen) bestehen, die erst in Verbindung mit Verknüpfungen verständlich werden. Der eigene Schlüssel des Datensatzes wird dabei als Primärschlüssel bezeichnet. Andere Schlüssel im Datensatz, die auf die Primärschlüssel anderer Tabellen verweisen, werden als Fremdschlüssel bezeichnet.
Schlüssel können auch aus einer Kombination mehrerer Angaben bestehen. Z. B. können die Teilnehmer einer Vorlesung durch die eindeutige Kombination von Vorlesungsnummer und Studentennummer identifiziert werden, so dass die doppelte Anmeldung eines Studenten zu einer Vorlesung ausgeschlossen ist.
Referenzielle Integrität bedeutet, dass Datensätze, die von anderen Datensätzen verwendet werden, in der Datenbank auch vollständig vorhanden sind.
Diese wichtige Funktionalität kann (und sollte) bereits von der Datenbank überwacht werden, so dass z. B.
Widersprüchlichkeit von Daten wird allgemein als Dateninkonsistenz bezeichnet. Diese besteht, wenn Daten bspw. die Integritätsbedingungen (z. B. Constraints oder Fremdschlüsselbeziehungen) nicht erfüllen.
Ursachen für Dateninkonsistenzen können Fehler bei der Analyse des Datenmodells, fehlende Normalisierung des ERM oder Fehler in der Programmierung sein.
Zum letzteren gehören die Lost-Update-Phänomene sowie die Verarbeitung von zwischenzeitlich veralteten Zwischenergebnissen. Dies tritt vor allem bei der Online-Verarbeitung auf, da dem Nutzer angezeigte Werte nicht in einer Transaktion gekapselt werden können.
Beispiel: Transaktion A liest Wert x Transaktion B verringert Wert x um 10 Transaktion A erhöht den gespeicherten Wert von x um eins und schreibt zurück Ergebnis x' = x+1 Die Änderung von B ist verloren gegangen
In den oben vorgestellten Befehlen
create table
und alter
table
wird bei der Definition jeder Spalte angegeben,
welchen Datentyp die Werte dieser Spalte annehmen können. Dazu
liefert SQL eine ganze Reihe standardisierter Datentypen mit. Die
einzelnen DBMS-Hersteller haben diese Liste jedoch um eine Unzahl
weiterer Datentypen erweitert. Die wichtigsten Standarddatentypen sind:
integer
numeric (n, m)
oder decimal (n, m)
n
Stellen, davon m
Nachkommastellen. Wegen der hier erfolgenden Speicherung als Dezimalzahl ist eine besonders für Geldbeträge notwendige Genauigkeit gegeben.float (m)
m
Nachkommastellen.real
double
oder double precision
float
und double
character (n)
oder char (n)
n
Zeichen.varchar (n)
oder character varying (n)
n
druckbaren und/oder nicht druckbaren Zeichen. Die Variante varchar2
ist für Oracle spezifisch, ohne dass sie sich tatsächlich unterscheidet.text
clob
.date
time
timestamp
boolean
true
(wahr) oder false
(falsch) annehmen). Dieser Datentyp ist laut SQL:2003 optional und nicht alle DBMS stellen diesen Datentyp bereit.blob (n)
oder binary large object (n)
n
Bytes Länge.clob (n)
oder character large object (n)
n
Zeichen Länge.Wenn es die Tabellendefinition erlaubt, können Attribute auch den Wert
NULL
annehmen, wenn kein Wert bekannt ist oder
aus anderen Gründen kein Wert gespeichert werden soll. Der
NULL
-Wert ist von allen anderen möglichen
Werten des Datentyps verschieden.
Eine Transaktion bezeichnet eine Menge von Datenbankänderungen, die zusammen ausgeführt werden (müssen). So ist beispielsweise die Buchung (als Transaktion) eines Geldbetrags durch zwei atomare Datenbankoperationen „Abbuchen des Geldbetrages von Konto A“ und „Buchung des Geldbetrages auf Konto B“ gekennzeichnet. Kann die vollständige Abarbeitung der elementaren Datenbankoperationen der Transaktion nicht durchgeführt werden (z. B. aufgrund eines Fehlers), müssen alle durchgeführten Änderungen an dem Datenbestand auf den Ausgangszustand zurückgesetzt werden.
Der Vorgang, der alle Änderungen einer Transaktion zurücksetzt, wird als Rollback bezeichnet. Der Begriff Commit bezeichnet das Ausführen einer Transaktion. Transaktionen sind eine Möglichkeit, die Konsistenz des Datenbestandes zu sichern. Im Beispiel der doppelten Kontenführung wird durch das Verhindern von ungültigen Teilbuchungen eine ausgeglichene Kontobilanz gewährleistet.
Datenbanken erlauben es zum Teil, bestimmte Befehle außerhalb einer Transaktion auszuführen. Darunter fällt insbesondere das Laden von Daten in Tabellen oder das Exportieren von Daten mittels Utilities. Manche DBMS erlauben das temporäre Abschalten der Transaktionslogik sowie einiger Kontrollen zur Erhöhung der Verarbeitungsgeschwindigkeit. Dies muss allerdings meist durch einen expliziten Befehl erzwungen werden, um ein versehentliches Ändern von Daten außerhalb einer Transaktion zu vermeiden. Solche Änderungen können, falls eine Datenbankwiederherstellung erforderlich ist, zu schweren Problemen oder gar Datenverlusten führen.
Eine Transaktion wird mit der SQL-Anweisung Commit
beendet. Alle Änderungen der Transaktion werden persistent gemacht, und das DBMS stellt durch geeignete (interne) Mittel (z. B. Logging) sicher, dass diese Änderungen nicht verloren gehen.
Mit dem Befehl Rollback
wird eine Transaktion ebenfalls beendet, es werden jedoch alle Änderungen seit Beginn der Transaktion rückgängig gemacht. Das heißt, der Zustand des Systems (in Bezug auf die Änderungen der Transaktion) ist der gleiche wie vor der Transaktion.
Das ursprüngliche SQL war keine Turing-vollständige Programmiersprache, es ermöglichte also nicht die Realisierung von beliebigen Computerprogrammen. Mittlerweile lässt es sich mit anderen Programmiersprachen kombinieren, um eine Programmierung im engeren Sinne zu ermöglichen. Hierfür gibt es unterschiedliche Techniken.
Unabhängig von der verwendeten Programmiertechnik wird zwischen statischem und dynamischem SQL unterschieden.
Bei dynamischem SQL muss das Datenbanksystem die SQL-Anweisung zur Laufzeit des Programms interpretieren und den Zugriffspfad optimieren. Da dieser so genannte Parse-Vorgang Zeit in Anspruch nimmt, puffern viele Datenbanksysteme die bereits geparsten SQL-Anweisungen, um so, falls sie sich wiederholen, die Zeit für ein erneutes Parsen zu sparen. Bei statischem SQL kann schon bei der Übersetzung der Programme bzw. beim Binden der SQL-Anweisungen an eine Datenbank (so genanntes Bind der SQL-Befehle) der optimale Zugriffsweg bestimmt werden. Damit sind kürzestmögliche Laufzeiten der Anwendungsprogramme möglich, allerdings muss der Zugriffsweg aller betroffenen Programme neu bestimmt werden, wenn sich Voraussetzungen (z. B. Statistiken) ändern (Rebind). Die Bind-Phase ist heute vor allem im Großrechner-Umfeld bekannt, die meisten Datenbanksysteme optimieren hingegen zur Laufzeit.
Ziel der Standardisierung ist es, Anwendungsprogramme so erstellen zu können, dass sie vom verwendeten Datenbanksystem unabhängig sind. Heutige Datenbanksysteme implementieren mehr oder weniger große Teile des Sprachstandards. Darüber hinaus stellen sie oftmals herstellerspezifische Erweiterungen bereit, die nicht dem Standard-Sprachumfang entsprechen. In der Vor-SQL-Zeit strebte man die Portabilität von Anwendungen über die kompatible Schnittstelle an.
Der Standard besteht insgesamt aus 9 einzelnen Publikationen[3]:
und wird durch 5 bzw. 6 ebenfalls standardisierte SQL multimedia and application packages ergänzt:
Der offizielle Standard[4] ist nicht frei verfügbar, jedoch existiert ein Zip-Archiv mit einer Arbeitsversion von 2008.[5]
Die beiden ersten Teile des SQL Standards SQL/Framework und SQL/Foundation legen die Kernfunktionalitäten fest. In den weiteren Teilen werden spezifische Aspekte der Sprache definiert.
Als Ergänzung zum SQL-Standard existiert mit ISO/IEC 13249: SQL multimedia and application packages eine Norm, die für die Anwendungsfälle Text, Geografische Daten, Bilder, Data mining und Metadaten spezialisierte Schnittstellen in SQL Syntax festlegt.