SQL

relationale Datenbank-Abfragesprache
Dies ist eine alte Version dieser Seite, zuletzt bearbeitet am 7. September 2005 um 15:57 Uhr durch Dunkeltron (Diskussion | Beiträge) (Deklarative Sprache). Sie kann sich erheblich von der aktuellen Version unterscheiden.

Structured Query Language (SQL), zu deutsch strukturierte Abfragesprache, ist eine deklararive Abfragesprache für Relationale Datenbanken. Sie hat eine relativ einfache Syntax, die an die englische Umgangssprache angelehnt ist, und stellt eine Reihe von Befehlen zur Definition von Datenstrukturen nach der Relationalen Algebra, zur Manipulation von Datenbeständen (Anfügen, Bearbeiten und Löschen von Datensätzen) und zur Abfrage von Daten zur Verfügung. Durch ihre Rolle als Quasi-Standard ist SQL von großer Bedeutung, da eine weitgehende Unabhängigkeit von der benutzten Software erzielt werden kann. Die meisten SQL-Implementierungen bieten darüber hinaus allerdings noch herstellerspezifische Erweiterungen, die nicht dem Standard-Sprachumfang entsprechen, was zur Folge hat, dass von den Herstellern parallel entwickelte gleiche Funktionen unterschiedliche Sprachelemente benutzen.

Viele bekannte Datenbanksysteme wie DB2, Microsoft SQL Server, MySQL, Oracle, PostgreSQL, Borland Interbase, Firebird und die neueren Versionen von Access implementieren Teile des SQL Sprachstandards.

Sprachschichten und Beispiele

Die Datenbanksprache SQL lässt sich in vier eigenständige Sprachschichten einteilen: die Data Query Language (DQL, Datenabfrage), die Data Control Language (DCL, Rechteverwaltung), die Data Manipulation Language (DML, Datenmanipulation) und die Data Definition Language (DDL, Datendefinition).

Data Query Language: SELECT

Die SELECT-Anweisung startet eine Abfrage. Aufgrund der Syntax kann eine SELECT-Anweisung auch als "SFW-Block" (SELECT, FROM, WHERE) bezeichnet werden. Syntax (unvollständig):

SELECT [DISTINCT] Auswahlliste
FROM Quelle
WHERE Where-Klausel
[GROUP BY (Group-by-Attribut)+
[HAVING Having-Klausel]]
[ORDER BY (Sortierungsattribut)+ [ASC|DESC]]
  • DISTINCT gibt an, dass aus der Ergebnisrelation gleiche Ergebnistupel entfernt werden sollen. Sonst liefert SQL eine Multimenge zurück.
  • Auswahlliste bestimmt, welche Spalten der Quelle auszugeben sind (* für alle) und ob Aggregatfunktionen anzuwenden sind.
  • Quelle gibt an, wo die Daten herkommen. Es können Relationen und Sichten angegeben werden und diese miteinander als kartesisches Produkt oder als Verbund (JOIN, ab SQL-92) verknüpft werden. Mit der zusätzlichen Angabe eines Namens können Tupelvariablen besetzt werden, d.h. Relationen für die Abfrage umbenannt werden (vgl. Beispiele).
  • Where-Klausel bestimmt Bedinungen, unter denen die Daten ausgegeben werden sollen. In SQL (außer MySQL <=3) ist hier auch die Angabe von Unterabfragen möglich, so dass SQL streng relational vollständig wird.
  • Group-by-Attribut listet Attribute auf, auf die Aggregationsfunktionen zusammen angewendet werden sollen. Fehlt diese Klausel, werden Aggregationsfunktionen auf alle Tupel angewendet.
  • Having-Klausel ist wie die Where-Klausel, nur dass hier auch auf Aggregationsfunktionen zugegriffen werden kann (wie z.B. in HAVING sum(Betrag)>0).
  • Sortierungsattribut, nach ORDER BY werden Attribute angegeben, nach denen sortiert werden soll. ASC gibt dabei aufsteigende (Standard), DESC absteigende Sortierung an. Ein Sortierungsattribut muss in der Auswahlliste vorkommen.
  • Ein oder mehrere SFW-Blöcke können außerdem mittels UNION vereinigt werden, wenn die Attribute gleich sind.

Beispiele:

SELECT * FROM Adressen;

Listet die Werte aller Spalten aus der Tabelle Adressen auf.

SELECT Name, Vorname, Postleitzahl FROM Adressen;

Projektion: Listet nur die Spalten Name, Vorname und Postleitzahl der Tabelle Adressen auf.

SELECT Name, Vorname, Postleitzahl AS PLZ FROM Adressen;

Projektion mit Umbenennung: Die Spalte heißt in der Ergebnisrelation jetzt PLZ.

SELECT Name, Vorname FROM Adressen WHERE Ort='Hannover';

Selektion: Listet nur die Hannoveraner auf.

SELECT a.Name, a.Vorname, a.Plz, a.Ort FROM Adressen a NATURAL JOIN Namenliste;

Natürlicher Verbund: Listet die Werte der Spalten Name, Vorname, Plz und Ort aus der Tabelle Adressen für alle Namen die auch in der Tabelle Namenliste vorkommen auf.

SELECT a.Strasse

FROM Adressen a LEFT OUTER JOIN Leute l ON l.Strasse=a.Strasse

WHERE l.Strasse IS NULL;

Äußerer linker Theta-Verbund: Listet alle Straßen auf, in denen niemand wohnt.

SELECT a.Strasse

FROM Adressen a

WHERE NOT EXISTS (SELECT * FROM Leute WHERE Strasse=a.Strasse)

Unterabfrage mit Existenz-Quantor: Das gleiche mit einer Unterabfrage.

SELECT Jahr, Quartal, SUM(Betrag) AS Umsatz FROM Rechnung GROUP BY Jahr, Quartal;

Gruppierung und Aggregation: Summiert die Spalte Betrag der Tabelle Rechnung und listet das Ergebnis Quartalsweise.

Fehlende: HAVING

Data Manipulation Language: INSERT, UPDATE, DELETE

Die DML enthält Befehle zur Datenmanipulation. Syntax:

INSERT INTO Relation ['(' (Attribut)+ ')'] VALUES '('(Konstanten)+')'
INSERT INTO Relation ['(' (Attribut)+ ')'] SFW-Block
UPDATE Relation SET (Attribut=Ausdruck)+ WHERE Where-Klausel
DELETE FROM Relation [WHERE Where-Klausel]
  • Mit INSERT können explizit konstruierte Tupel oder die Ergebnisse eines SFW-Blocks in eine Relation eingefügt werden.
  • Ausdruck aus der UPDATE-Anweisung kann insbesondere auch auf das zu manipulierende Attribut bezug nehmen wie z.B. in UPDATE Personal SET Gehalt=Gehalt*2 WHERE Abteilung='EDV'
  • Wird bei DELETE die WHERE-Klausel weg gelassen, wird die ganze Relation gelöscht, aber nicht das Schema.

Beispiele:

insert into Adressen (Name, Vorname, Ort) values ('Schroeder', 'Kurt', 'Köln');

Fügt eine Zeile mit den geg. Werten für die Spalten Name, Vorname und Ort in die Tabelle Adressen hinzu.

insert into Adressen values ('Schroeder', 'Knut', 'Köln');

Beim insert-Statement kann die erste Klammer mit den Attribut-Namen auch weggelassen und direkt mit values() die Werte eingefügt werden. Allerdings müssen dann die Werte in der gleichen Reihenfolge wie in der Tabellendefinition angegeben werden.

insert into Adressen (Name, Vorname, Ort) select Nachname, Vorname, Ort from Alte_Adressen;

Lädt alle Adressen aus der Tabelle Alte_Adressen in die Tabelle Adressen.

update Adressen set Ort='Berlin', Telefon='030...' where Name='Schroeder';

Ändert den Wert in der Spalte Ort aller Einträge auf "Berlin" (Telefon auf ... usw), wenn der Wert in der Spalte Name "Schroeder" lautet.

delete from Adressen;

Löscht alle Zeilen aus der Tabelle Adressen.

delete from Adressen where name='Müller';

Löscht alle Zeilen aus der Tabelle Adressen, deren Wert in der Spalte Name "Müller" lautet.

truncate table Adressen;

Leert die Relation, wird aber nur von einigen DBMS unterstützt. Im Gegensatz zu delete nicht transaktionssicher.

Data Definition Language: CREATE, ALTER, DROP

Die DDL enthält Befehle zur Datendefinition. Syntax (primary key und foreign key sind teil der SQL-89 IDL bzw. SQL-92 und werden z.B. von MySQL nicht unterstützt):

CREATE TABLE Relation '(' (Attribut-Definition)+ ')'
CREATE TABLE Relation '(' (Attribut-Definition [PRIMARY KEY])+
 [, FOREIGN KEY '(' (Attribut)+ ')' REFERENCES Relation '(' (Attribut)+ ')'] ')'
DROP TABLE Relation
ALTER TABLE Relation Alter-Definition
CREATE INDEX Index-Name ON Relation '(' (Attribut)+ ')'
DROP INDEX Index-Name
CREATE VIEW Sicht ['(' (Attribut)+ ')'] AS SFW-Block [WITH CHECK OPTION]
DROP VIEW Sicht
  • Die Attribut-Definition enthält den Namen des Attributes, den Datentyp, sowie optionale Angaben wie NOT NULL. In SQL-92 können benutzerdefinierte Wertebereiche sowie Defaultwerte angegeben werden.
  • Bei CREATE TABLE können ab SQL-92 außerdem mittels der CHECK-Klausel noch Integritätsbedingungen bei den Attributen oder für die Tabelle angegeben werden.
  • Die Alter-Definition ist ADD Attribut-Definition. In SQL-92 gibt es noch ALTER Attribut Default-Wert oder DROP Attribut. Da SQL-92 sehr restriktiv bzgl. der ALTER-ALTER-Anweisung ist, ist dies eine der Anweisungen, die von den Herstellern universell erweitert wurde, so dass beliebige Änderungen möglich sind wie durch eine Folge von DROP und ADD-Anweisungen.
  • Bei der Definition einer Sicht können neue Attributnamen vergeben werden. SFW-Block ist eine beliebige SQL-Abfrage, WITH CHECK OPTION gibt an, ob gewisse Änderungsoperationen erlaubt sein sollen (vgl. Sichten).
  • Die CREATE-Anweisung wird in modernen DBMS dazu benutzt, außer Relationen, Indizies und Sichten alle möglichen anderen Objekte zu kreieren.

Beispiele:

create table Laender (Kuerzel_ISO character(2) primary key, Land_Name varchar(50) NOT NULL);

Erzeugt eine neue Tabelle namens Laender mit den Spalten Kuerzel_ISO und Land_Name, wobei Kuerzel_ISO der Primärschlüssel ist und in keiner der Spalten leere Felder erlaubt sind.

alter table Laender add Kuerzel_Auto varchar(3);

Definiert eine neue Spalte namens Kuerzel_Auto in der Tabelle Laender.

drop table Adressen;

Löscht die gesamte Tabelle Adressen.

create index idx_Adressen on Adressen (Name);

Legt einen Index auf die Spalte Name der Tabelle Adressen. Der Index bekommt die Bezeichnung idx_Adressen und beschleunigt die Suche nach Datensätzen in der Tabelle Adressen, wenn der Name als Suchkriterium angegeben wird.

drop index idx_Adressen;

Löscht den Index idx_Adressen.

Data Control Language: GRANT and REVOKE

Die DCL enthält Befehle zur Vergabe von Rechten. Die Befehle manipulieren Access Control Lists auf Datenbankobjekten. Syntax:

GRANT (Operation)+ ON Relation TO (PUBLIC|Benutzer) [WITH GRANT OPTION]
REVOKE (Operation)+ ON Relation FROM (PUBLIC|Benutzer)
  • Relation kann insbesondere auch eine Sicht sein.
  • WITH GRANT OPTION erlaubt es den neuen Rechteinhabern, das Recht weiter zu geben.
  • PUBLIC bezeichnet alle Benutzer.
  • Der Datenbankadministrator (DBA) hat alle Rechte. Der Besitzer eines Objektes hat auch alle Rechte an diesem Objekt.
  • Die Kommandos zur Rechteverwaltung sind in SQL spezifiziert, nicht jedoch die zur Benutzerverwaltung. Daher implementiert jedes DBMS seine eigene Benutzerverwaltung, die Rollennamen und/oder Benutzergruppen kennen mag oder auch nicht.
  • In modernen DBMS können Rechte auf alles mögliche vergeben werden, nicht nur auf einzelne Tabellen.

Beispiele:

grant select,update on table Adressen to groupx;

Gestattet dem Benutzer bzw. der Gruppe groupx einen lesenden und ändernden Zugriff auf die Tabelle Adressen.

revoke execute on procedure DSN8ED6 from public;

Entzieht allen nicht explizit berechtigten Benutzern das Recht, die Stored-Procedure DSN8ED6 auszuführen. Berechtigungen, die einem Benutzer oder einer Gruppe erteilt wurden, bleiben bestehen.

SQL-Datentypen

In den oben vorgestellten Befehlen create table und alter table wird bei der Definition jeder Spalte angegeben, welches Datenformat sie unterstützen soll. Dazu liefert SQL eine ganze Reihe standardisierter Datentypen mit. Die einzelnen DBMS-Hersteller haben diese Liste jedoch um eine Unzahl weiterer Datentypen erweitert, woraus die nützlichsten wohl TEXT und BLOB sein dürften. Die wichtigsten Standarddatentypen sind:

integer

Ganze Zahl (positiv oder negativ)

number (n)

Ganze Zahl (positiv oder negativ) mit maximal n Stellen

number (n, m) oder decimal (n,m)

Festkommazahl (positiv oder negativ) mit maximal n Stellen, davon m nach dem Komma

float (m)

Gleitkommazahl (positiv oder negativ) mit maximal m Stellen nach dem Komma

character (n) oder char (n)

Zeichenkette (also Text) mit n druckbaren und/oder nicht druckbaren Zeichen

varchar (n), varchar2 (n)

Zeichenkette (also Text) von variabler Länge, aber maximal n druckbaren und/oder nicht druckbaren Zeichen. Die Variante varchar2 ist für Oracle spezifisch.

date

Datum (bei Oracle inklusive Uhrzeit)

boolean

Boolesche Variable (kann die Werte true (wahr) oder false (falsch) annehmen). Dieser Datentyp fehlt in Oracle.

raw (n)

Binärdaten von maximal n Bytes Länge.

Fachbegriffe

Die folgenden Fachbegriffe sind zum Verständnis von SQL hilfreich. Sie sind jedoch auch als eigenständige Begriffe der Informatik bedeutsam und werden nicht nur im Kontext von SQL verwendet.

In jeder Tabelle sollte grundsätzlich ein Primärschlüssel (primary key) definiert werden. Dieser ist entweder der natürliche Schlüssel der Tabelle oder ein künstlicher, beispielsweise ein Zähler, der pro Datensatz hoch gezählt wird. Dieser Schlüssel ermöglicht es, dass jeder Datensatz innerhalb der Tabelle eindeutig ist. Über den Schlüssel kann man den Datensatz eindeutig identifizieren. Ein Primärschlüssel kann auch aus mehreren Attributen (Spalten) der Tabelle bestehen (zusammengesetzter Primärschlüssel). In dieser Tabelle haben je zwei Datensätze immer auch unterschiedliche Schlüssel.

Der Primärschlüssel muss aus einem Merkmal oder einer minimalen Merkmalskombination (bei zusammengesetzten Primärschlüsseln) bestehen. Die Bedingung der minimalen Merkmalskombination bei zusammengesetzten Primärschlüsseln bedeutet, dass ein Teil (Merkmal) des zusammengesetzten Schlüssels nicht reichen darf, um ein Tupel eindeutig zu identifizieren.

Fremdschlüssel (auch Foreign Key genannt) bezeichnen im Bereich der relationalen Datenbanken ein Attribut einer Relation (Tabelle), das auf den Primärschlüssel einer anderen Relation verweist. Ein Fremdschlüssel kann, muss aber nicht Primärschlüssel seiner Relation sein.


Loggt man sich in eine Datenbank ein, kann man Änderungen an den Tabellen oder den Daten vornehmen. Grundsätzlich ist in einer relationalen Datenbank alles innerhalb einer Transaktion zu sehen.

Datenbanken erlauben zum Teil bestimmte Befehle außerhalb einer Transaktion auszuführen. Darunter fällt insbesondere das Laden von Tabellen, oder das Entfernen 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 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 Datenverlust führen. Eine Transaktion beendet man mit dem Befehl Commit. Mit dem Befehl Rollback wird die Transaktion ebenfalls beendet, es werden jedoch alle (Daten-)Änderungen seit Beginn der Transaktion wieder rückgängig gemacht. Technische Änderungen bleiben in der Regel erhalten (so genannte Kompaktierung, compaction).

Eine nicht Übereinstimmung von Daten nennt man Dateninkonsistenz. Das passiert immer dann, wenn bspw. eine Tabelle auf einen Wert einer anderen Tabelle weist, dieser Wert jedoch nicht mehr vorhanden oder geändert worden ist.

Die häufigsten Gründe für Dateninkonsistenzen sind falsche Analyse des Datenmodells während der Normalisierung des ERM oder Fehler in der Programmierung.

Zum letzteren gehören die Lost-Update-Phänomene sowie die Verarbeitung von zwischenzeitlich veralteten Zwischenergebnissen. Dies tritt vor allem bei Online-Verarbeitung auf, da dem Nutzer angezeigte Werte nicht transaktionsmäßig 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

Von referentieller Integrität spricht man, wenn jeder Fremdschlüssel einer Tabelle einen entsprechenden Primärschlüssel einer anderen Tabelle zugeordnet, oder der Wert des Fremdschlüssels NULL ist.

Um eine Dateninkonsistenz zu vermeiden, verknüpft man die Tabellen untereinander. Über die Verbindung mit Fremdschlüssen kann man nun angeben, was passieren soll, wenn ein verknüpfter Datensatz gelöscht oder geändert wird. Beim Löschen kann man zum Beispiel eine Kaskadierung des Löschens auf alle über Fremdschlüssel verknüpften Datensätze oder das Verbieten des Löschvorgangs erreichen. Beim Update kann man die Änderung in den referenzierenden Tabellen ebenfalls durchführen.

Ein Update von Primärschlüsseln (PK-Update) ist zwar von Codd vorgesehen, er widerspricht jedoch gleichzeitig der Notwendigkeit eines PK-Updates, da ein Primärschlüssel stets unveränderlich ist.

Ein Grundsatz einer Datenbank ist, dass innerhalb einer Datenbank keine Redundanzen auftreten sollen. Man spricht dann von einer redundanzfreien Datenbank. Dies geschieht durch die Normalisierung.

Da eine Datenbank, die allen Anforderungen der 3. oder sogar 5. Normalform entspricht, in der Praxis bedingt durch Performanceprobleme nicht zu verwenden wäre, werden nachträglich 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.

Ein Merkmal der Redundanz ist, wenn einzelne Werte innerhalb einer Tabelle oder Datenbank ohne Informationsverlust weggelassen werden können. Redundanz kostet nicht nur Speicherplatz sondern kann Ursache für Anomalien (z.B. Update-, Insert-, Delete-Anomalien) sein, diese werden auch als "Mutationsanomalien" bezeichnet.

Statisches und dynamisches SQL

Die meisten Datenbanken, welche SQL unterstützen, unterscheiden zwischen statischem und dynamischem SQL. Bei statischem SQL sind die SQL-Anweisungen fest in einem Anwendungsprogramm kodiert (so genanntes Embedded SQL). Während der Programmvorbereitung übersetzt ein Precompiler die SQL-Befehle in Funktionsaufrufe, anschließend definiert ein Anfrageoptimierer den besten Zugriffspfad auf die Daten und speichert diesen im Datenbanksystem ab.

Dynamisches SQL wird dagegen während der Laufzeit eines Programms interpretiert und der Zugriffspfad wird bei jedem Durchlauf neu optimiert. Da im Durchschnitt der Parsevorgang einer SQL-Anweisung etwa ein Drittel der gesamten Laufzeit in Anspruch nimmt, puffern jedoch viele Datenbanken die bereits geparsten SQL-Anweisungen um, falls sie sich wiederholen, die Zeit für ein erneutes Parsen zu sparen.

Beide Arten von SQL haben ihre Vor- und Nachteile. Statisches SQL mit voroptimierten Zugriffen verhindert unliebsame Überraschungen, da der Ausführungsplan nur bei einem sog. Rebind neu berechnet wird und die Existenz der Objekte, die syntaktische Korrektheit und die Berechtigungen schon beim Binden geprüft werden. Statisches SQL wird heute fast nur noch (und dort auch vorwiegend) in Mainframe Umgebungen verwendet. In den meisten anderen Umgebungen kommt dynamisches SQL zum Einsatz, welches erlaubt Abfragen innerhalb eines Programms zu generieren. Mit dem SQLJ-Standard wird zunehmend auch in JAVA statisches SQL eingesetzt. Darüber hinaus hat JDBC die Möglichkeit der prepared Statements.

Der Ausführungsplan von statischem wie dynamischem SQL wird (falls ein kostenbasierter Anfrageoptimierer verwendet wird) anhand von vorhandenen Tabellenstatistiken berechnet. Fehlen diese Statistiken oder sind sie falsch bzw. veraltet, ist der Ausführungsplan unperformant und führt meist zu unnötig langen Antwortzeiten.

Erweiterungen

Es existieren eine Vielzahl von Erweiterungen des SQL-Standards.

SQL/XML ist ein ANSI und ISO Standard (ISO/IEC 9075-14), der es ermöglicht, XML-Dokumente in SQL-Datenbanken zu speichern, mit XPath und XQuery abzufragen und relationale Datenbankinhalte als XML zu exportieren. [1] Der ISO-Standard ist nicht frei verfügbar, jedoch gibt es ein zip Archiv mit einer Draft-Version von 2003.

Siehe auch

Literatur

Obwohl bereits etwas betagt, ist dieses Buch gerade als wissenschaftlich fundierte und trotzdem leicht verständliche Einführung in SQL sehr zu empfehlen.

Vorlage:Wikibooks1