4Datendefinition in SQL

Werbung
4
Datendefinition in SQL
SQL hat sich als Standardabfragesprache für relationale Datenbanken etabliert.
SQL steht ursprünglich für »Structured Query Language«. Die ersten Versuche
dazu wurden in den IBM-Labors vorgenommen und daraus ist die Vorläufersprache SEQUEL entstanden. SQL stellt die Schnittstelle zwischen der relationalen
Datenbank und dem Anwendungsprogramm dar. Die Sprache ist in erster Linie
nicht für Endanwender gedacht, sondern für Systementwickler. Mit SQL lassen
sich alle Operationen der Relationenalgebra realisieren, die in Kapitel 3 eingeführt
worden sind.
4.1 SQL und SQL-Standard
4.1.1 Ein kleiner Überblick über die Historie von SQL
1974
D. Chamberlain et. al. definieren SEQUEL.
1977
Revision: SEQUEL/2; IBM-Prototyp System R.
1977
Oracle beginnt mit der Implementierung von SEQUEL auf Mainframes.
1979
Oracle liefert ein erstes relationales Datenbanksystem mit SQL aus.
1981
IBM liefert SQL/DS aus.
1983
IBM stellt DB2 vor.
1985
Ingres stellt auf SQL um.
Informix stellt auf SQL um.
1986
Sybase wird ausgeliefert.
1986
X/OPEN entscheidet sich für SQL.
1987
Der Standard ISO 9075 Database Language SQL (SQL-86) wird veröffentlicht.
1988
dBASE IV erhält SQL als Abfrage-Sprache.
Adabas erhält SQL.
1989
ISO 9075 Database Language SQL with Integrity Enhancement (SQL-89)
wird veröffentlicht.
SESAM und UDS erhalten SQL.
151
4 Datendefinition in SQL
1992
ISO 9075 Database Language SQL (SQL2 oder SQL-92) wird veröffentlicht.
1993
RDA-Standard (Remote Data Access) der Database Access Group (z.B.
Microsoft ODBC) wird veröffentlicht.
1996
SQL/PSM (Persistent Stored Modules); Datenbankprozeduren werden
normiert (vgl. Kapitel 7.3).
1999
SQL:1999 wird veröffentlicht und löst damit SQL-92 ab.
2003
Eine abermals überarbeitete und teilweise neu strukturierte Version
SQL:2003 löst SQL:1999 ab. Zum Zeitpunkt der Drucklegung dieses
Buchs befindet sich die neue Norm aber noch im Entwurfsstadium und
wird von Pessimisten (oder Realisten) als SQL:200n bezeichnet.
Zwischen dem SQL-Standard und den in kommerziell verfügbaren Datenbanksystemen angebotenen SQL-Implementierungen gibt es Differenzen in beiden Richtungen. Teilweise übersteigt der verfügbare Sprachumfang die Forderungen der
Norm, teilweise werden Forderungen der SQL-Norm nicht erfüllt. Es ist aber
grundsätzlich zu erkennen, dass die Hersteller sich mehr und mehr um die Einhaltung des SQL-Standards bemühen.
Die Standardisierung von SQL ist aus folgenden Gründen wichtig:
왘 Verschiedene RDBMs können nebeneinander im Betrieb existieren. Die Anwen-
dungsentwicklung und Datenbankadministration sollten möglichst wenig voneinander abweichen.
왘 Anwendungen sollen portabel sein, damit man beispielsweise auf ein leis-
tungsfähigeres DBMS umsteigen kann oder damit die Anwendungsentwicklung in einer anderen Umgebung erfolgen kann als der produktive Einsatz.
왘 Herstellerunabhängigkeit ist gefordert.
왘 Die Verfügbarkeit von »Front-Endsystemen«, also Programmen, die hersteller-
unabhängig auf Datenbanken zugreifen können, nimmt zu.
왘 In Client-Server-Umgebungen kommuniziert die Anwendersoftware über
Schnittstellen mit dem DBMS.
왘 Bei der Anwendungsentwicklung mit CASE-Tools erfolgt die Festlegung von
Daten- und Programmstrukturen über weite Strecken unabhängig vom eingesetzten DBMS.
4.1.2 Elemente von SQL
Die Sprachelemente von SQL lassen sich in zwei Kategorien unterteilen, die allerdings im Standard nicht festgeschrieben sind:
152
SQL und SQL-Standard
DDL (Data Definition Language)
Hierzu gehören:
왘 Anweisungen zur Anlage und Verwaltung von Schemata (Zusammenfassung
von Tabellen, Datensichten etc.), für die ein bestimmter Benutzer zuständig ist
왘 Anweisungen zur Definition von Domänen
왘 Anweisungen zur Definition von Relationen einschließlich der dazugehörigen
Konsistenzbedingungen
왘 Anweisungen zur Anlage von Datensichten (Views)
왘 Die Verwaltung von Benutzern und deren Datenzugriffsrechten
DML (Data Manipulation Language)
Die DML enthält Anweisungen zur:
왘 Eingabe von Daten in eine vorhandene Tabelle
왘 Änderung von Daten in einer Tabelle
왘 Löschung von Daten in einer Tabelle
왘 Abfrage von Daten, die auch mehrere Tabellen umfassen können
und Anweisungen zur:
왘 Definition und Steuerung von Transaktionen
Weiterhin gehören zum Sprachumfang kommerziell verfügbarer relationaler
Datenbanksysteme Anweisungen, die die interne Organisation der Datenbanken
steuern. Sie sind syntaktisch meist an SQL-Anweisungen angelehnt, unterliegen
aber nicht der Norm, da diese sich nicht auf das interne Schema einer Datenbank
bezieht. Dazu gehören:
왘 Anweisungen zur Definition von Indexen
왘 Erweiterungen der CREATE TABLE-Anweisung im Hinblick auf Varianten der
Ablage auf dem Speichermedium (beispielsweise in »Clustern«)1
SQL ist nicht-prozedural
Die gewünschten Daten werden unter SQL durch Prädikate (logische Bedingungen) charakterisiert. Entscheidend für das Auffinden der Daten, die man ansehen
oder verändern will, ist ihre Beschreibung über Attributwerte – wie kompliziert
diese auch immer sein mag. Ein Beispiel: Zeige von allen Kunden, deren Wohnort
Kayhude ist und die zugleich Stammkunden sind, Kunden_nr, Name und Ort an.
Der »Weg« zu den Daten in Form von Suchalgorithmen etc. wird bei SQL nicht
angegeben. Deshalb ist der Befehl zu obigem Beispiel relativ nahe an der
umgangssprachlichen Formulierung:
1 Das beispielsweise bei ORACLE vorhandene Cluster-Konzept sieht die Speicherung von Tupeln verschiedener Tabellen, die häufig miteinander verbunden werden, physikalisch benachbart auf den Plattensektoren vor, um damit die Anzahl der Zugriffe zu reduzieren.
153
4 Datendefinition in SQL
SELECTkunden_nr, name, ort
FROM kunde
WHERE ort = 'Kayhude' AND status = 'S';
Auch höchst komplexe Abfragen können so gestellt und beantwortet werden, z.B.:
»Zeige alle Kunden, die zwischen dem 1.3.2003 und dem 31.3.2003 einen Umsatz von
mehr als 100 Euro gemacht haben, wobei sie aber keinen Tee gekauft haben dürfen und im
Vorjahr auch schon einmal etwas bestellt haben müssen.«2
SQL verarbeitet grundsätzlich Mengen von Tupeln. Eine Abfrage wie die obige hat
eine Tabelle mit keiner, einer oder beliebig vielen Zeilen als Ergebnis.3 Dies unterscheidet SQL von imperativen Programmiersprachen, die satzweise arbeiten, d.h.
mit einer Anweisung immer nur einen Datensatz zugleich lesen, schreiben, löschen
oder vergleichen können. SQL orientiert sich an der Relationenalgebra. Es muss
aber deutlich festgehalten werden, dass SQL nicht mit Relationen, sondern mit
Tabellen arbeitet. Relationen sind nurmehr ein Spezialfall von Tabellen. Wir haben
in Kapitel 3 gezeigt, dass die Relationenalgebra mit wenigen Modifikationen auf
Tabellen anwendbar ist.4 Es ist in SQL auch jederzeit möglich, eine Datenabfrage so
zu formulieren, dass das Ergebnis eine Relation ist, also keine mehrfach vorkommenden identischen Tupel enthält. Seit 1999 verarbeitet SQL außer Tabellen auch
Strukturen, die als objektrelational bezeichnet werden und für die einige Einschränkungen, wie wir sie in Kapitel 3 formuliert haben, nicht gelten. Mehr dazu
findet sich in Kapitel 9.
Wir beziehen uns im Wesentlichen auf SQL im Sinne des Standards SQL:200n auf
dem Stand von August 2002 (Draft Version). Da zum Zeitpunkt der Manuskripterstellung kein DBMS verfügbar ist, das den Standard vollkommen erfüllt, wird
gegebenenfalls auf Abweichungen und Besonderheiten bei existierenden DBMS
(Sybase, ORACLE, etc.) hingewiesen.
4.2 Schemadefinition
Ein SQL-Schema enthält Datenbankobjekte eines einzelnen Benutzers5 innerhalb
einer Datenbank. Dazu gehören unter anderem von ihm erzeugte Basistabellen,
2 Wir empfehlen dieses Beispiel hier nicht als Übung.
3 Zur Unterscheidung der Begriffe Tupel, Zeile, Attribut, Spalte, Relation und Tabelle vgl. Abschnitt 2.1.
4 Näheres findet sich in Kapitel 2.6.
5 Unter einem Benutzer verstehen wir einen in der Datenbank namentlich eingetragenen, mit bestimmten Zugriffsrechten ausgestatteten Anwender der Datenbank. Benutzer und Person sind
nicht unbedingt identisch. Einer Person können je nach Anwendungszusammenhang verschiedene Benutzernamen zugeordnet sein, beispielsweise einer für die Rolle als Datenbankadministrator und ein anderer für die normale Nutzung der Datenbank. Umgekehrt kann es
manchmal organisatorisch sinnvoll sein, einen Benutzernamen (z.B. GAST) einzurichten, unter dem sich verschiedene Personen anmelden können, um allgemein zugängliche Informationen abzufragen (Auskunftsysteme).
154
DDL: Datendefinition mit SQL
Datensichten und Integritätsbedingungen.6 Jedes Datenbankobjekt gehört zu
genau einem Schema, und jedes Schema gehört genau einem Benutzer. Ein Benutzer kann aber Eigentümer mehrerer Schemata sein. Datenbankobjekte müssen
innerhalb eines Schemas eindeutige Namen haben. Das bedeutet, dass in einer
Datenbank mehrere Schemata gleichzeitig existieren können und dass gleichnamige Datenbankobjekte in verschiedenen Schemata auftreten können.
Die Anweisung zur Anlage eines Schemas lautet in etwas vereinfachter Form:
CREATE SCHEMA schema AUTHORIZATION benutzer
Es folgen dann die Definitionsanweisungen zur Erzeugung beliebig vieler Datenbankobjekte innerhalb des neuen Schemas, das sind beispielsweise CREATE DOMAIN,
CREATE TABLE, CREATE VIEW in beliebiger Anzahl und Reihenfolge. Diese Anweisungen werden in den folgenden Abschnitten beschrieben.
Zur Schemadefinition muss gesagt werden, dass zurzeit die meisten Datenbanksysteme diese Anweisung nicht zur Verfügung stellen. Oft wird gar nicht logisch
zwischen Datenbank und Schema unterschieden, und die Anlage einer Datenbank
erfolgt nicht über eine SQL-Anweisung, sondern über spezielle Hilfsprogramme,
mit denen dann auch gleich noch Details der internen Ebene wie Name und Größe
der Plattendatei festgelegt werden.
4.3 DDL: Datendefinition mit SQL
Eine zentrale Forderung an eine relationale Datendefinitionssprache ist die Unterstützung von Integritätsbedingungen. SQL unterstützt Schlüssel (Primär- und
Kandidatenschlüssel), Fremdschlüssel und so genannte »Geschäftsregeln« – das
sind Integritätsregeln, die sich durch logische Bezüge von Daten auf andere Daten
ergeben. Für die Zuverlässigkeit der Daten ist beispielsweise die Eineindeutigkeit
aller Primär- und Kandidatenschlüsselwerte unverzichtbar – wie sollen wir sonst
einen bestimmten Kunden identifizieren? Wir stellen die entsprechenden Sprachelemente in diesem Kapitel vor. Seit 1992 wird eine rudimentäre Form von benutzerdefinierten Datentypen (»Domänen«7) unterstützt. SQL:2003 enthält auch
objektorientierte Elemente, die die so genannten »objektrelationalen Datenbanken« charakterisieren sollen. Dazu gehört die Möglichkeit, »echte« benutzerdefinierte Datentypen inklusive Zugriffsmethoden und Vergleichsoperatoren zu
erzeugen. Wir kommen auf diese Erweiterungen in Kapitel 9 zurück.
Allgemein gilt, dass die Erzeugung neuer Datenbankobjekte mit dem Schlüsselwort CREATE eingeleitet wird. Anweisungen zur Entfernung von Datenobjekten
beginnen mit dem Schlüsselwort DROP8.
6 Der Begriff »Datenbankobjekt« darf nicht mit dem Objektbegriff der objektorientierten Datenbankmodelle verwechselt werden (vgl. Kapitel 9).
7 Sie erfüllen aber nur einenTeil des im Abschnitt 2.1.2 eingeführten Domänenkonzeptes.
8 Wird in 4.3.7 kurz behandelt.
155
4 Datendefinition in SQL
4.3.1 Datentypen und Domänen
Eine Domäne ist vom theoretischen Konzept her die Menge zulässiger Werte, die
ein Attribut in einer Relation annehmen kann, verbunden mit einer Menge an
Operationen, die innerhalb der Wertemenge oder in Verbindung mit anderen Wertemengen ausgeführt werden kann.9
CREATE DOMAIN gehört zum Datendefinitionsteil von SQL. Die Syntax lautet in der
Grundform:10
CREATE DOMAIN domänenname [AS] datentyp
[default]
[bedingung]
Die Domänendefinition wird im Datenwörterbuch abgelegt. Jede Domäne muss
einen eindeutigen Namen erhalten. Die Bedingung, die den Wertebereich einschränkt, wird durch eine CHECK-Klausel definiert, in der eine Suchbedingung wie in der WHERE-Klausel der SELECT-Anweisung angegeben wird.
Dabei kann beispielsweise auch festgelegt werden, ob Nullmarken zulässig
sind. Wir sind allerdings der Auffassung, dass diese Festlegung gar nicht der
Domäne selbst zukommt, wenn diese eine Wertemenge beschreibt. NULL ist kein
Wert und kann daher auch nicht Element einer Wertemenge sein. Nullmarken
zuzulassen ist eine Frage der Attributdefinition. Dabei können für Attribute, die
sich auf dieselbe Domäne beziehen, auch unterschiedliche Festlegungen getroffen werden. Eine Kundennummer als Primärschlüssel darf keine Nullmarke
enthalten, dasselbe ist für Fremdschlüssel aber in bestimmten Fällen durchaus
denkbar.
Aus einem ähnlichen Grund gehört auch die Default-Klausel eigentlich nicht in
die Domänendefinition, sondern in die Spaltendefinition einer Tabelle mit CREATE
TABLE. Verschiedene Spalten können derselben Domäne angehören, aber unterschiedliche Vorgabewerte haben. Der SQL-Standard trifft unseres Erachtens den
Sinn der Sache hier nicht. Domänen sind hier letztlich nicht mehr als eine Abtrennung von Elementen der Spaltendefinition (CHECK), auf die von mehreren Spalten aus Bezug genommen werden kann.11
Das Problem der erlaubten und verbotenen Operationen ist nicht Bestandteil der
CREATE DOMAIN-Anweisung, sondern wird im Standard unter dem Titel »Abstrakte Datentypen« behandelt. Wir erläutern dieses Konzept in Kapitel 9.
9 Vergleiche Abschnitt 2.1.2.
10 Die formale Syntaxbeschreibung ist im Anhang A beschrieben.
11 Melton, Mitglied des Standardisierungskomitees, sagt dazu: »'We were once fans of SQL's
domain capabilities. However, they have proved to be less useful than originally hoped, and
future editions of the SQL standard may actually delete the facility entirely.« [Melt02 S. 98]
156
DDL: Datendefinition mit SQL
Beispiele für Domänendefinitionen: 12
CREATE DOMAIN Kunden_key
AS INTEGER
CHECK (VALUE > 100);
CREATE DOMAIN Kunden_status
AS CHAR(1)
CHECK (VALUE IN ('W', 'G', 'S'));
-'W': Werbemaßname - noch nicht als Kunde aufgetreten
-'G': Gelegenheitskunde
-'S': Stammkunde
CREATE DOMAIN Zahlungsart
AS CHAR(1)
CHECK (VALUE IN ('R', 'B', 'N', 'V', 'K'))
DEFAULT 'N';
-'R': Rechnung
-'B': Bankeinzug
-'N': Nachnahme
-'V': Vorkasse
-'K': Kreditkarte
Auf diese Festlegung kann bei der Tabellendefinition zurückgegriffen werden. Für
eine Spalte, die ihre Werte aus einer definierten Domäne bezieht, ersetzt die Nennung der Domäne dann die Typangabe.
Beispiel:
CREATE TABLE
kunden_nr
status
zahlung
...
);
kunde (
Kunden_Key NOT NULL
Kunden_Status,
Zahlungsart,
Sybase Adaptive Server Anywhere realisiert Domänen entsprechend dem Standard.
Statt des Schlüsselworts VALUE, das beim Standard für den Zugriff auf den Wert
anzuwenden ist, muss man dort einen beliebigen Bezeichner mit vorangestelltem @
einsetzen. Wir verwenden im Folgenden in Anlehnung an den Standard jeweils
den Bezeichner @VALUE.
12 Im SQL-Standard ist nicht geregelt, ob SQL-Anweisungen durch ein Satzzeichen abgeschlossen werden müssen. In den verschiedenen interaktiven SQL-Systemen (ISQL) hat sich das Semikolon als abschließendes oder als trennendes Satzzeichen etabliert. Wir werden im Folgenden SQL-Anweisungen jeweils durch ein Semikolon abschließen. Die Zeichen -- bedeuten,
dass der Rest der Zeile ein Kommentar ist.
157
4 Datendefinition in SQL
-- Domaindefinition in Sybase SQL
CREATE DOMAIN Kunden_status
AS CHAR(1)
CHECK (@VALUE IN ('W', 'G', 'S'));
Die Anweisung CREATE DISTINCT TYPE erreicht, dass Attribute nur dann direkt vergleichbar sind, wenn sie demselben DISTINCT TYPE angehören. Beispielsweise ist
ein Vergleich von Kundennummern mit Bestellnummern dann nicht ohne weiteres
möglich. Dies macht ja auch in der Regel keinen Sinn und ist meistens das Ergebnis
einer Verwechslung von Attribut-Bezeichnern. Die Definition eines DISTINCT
TYPE schließt aber wiederum keine Einschränkung eines Wertebereichs ein.
Beispiel:
CREATE DISTINCT TYPE typ_kunden_nr AS INTEGER
Falls doch ausnahmsweise so ein Vergleich vorgenommen werden soll, ist das
durch explizite Konvertierung auf den Ursprungstyp zu formulieren, was mit der
CAST-Anweisung geschehen kann.
Beispiel:
CAST(kunden_nr AS INTEGER)
DB2 implementiert dieses Konzept.
4.3.2 Datentypen in SQL
Es gibt die im Folgenden angegebenen Datentypen in SQL. Die Skalierungsgrößen
in der Klammer hinter dem Datentyp können in der Regel weggelassen werden. Es
werden dann Standardwerte eingesetzt, die bei numerischen Datentypen implementationsabhängig sind, bei Zeichen- und Bitketten jeweils 1, bei TIME 0 (d.h.
keine Unterteilung der Sekunde) und bei TIMESTAMP 6 (d.h. Genauigkeit auf Mikrosekunden).
Exakt numerisch
INTEGER
üblicherweise vier Byte
SMALLINT
üblicherweise zwei Byte
BIGINT
mindestens so groß wie INTEGER
NUMERIC(p,q)
Dezimalzahlen mit genau p Stellen, davon q hinter dem Dezimalpunkt
DECIMAL(p,q)
Dezimalzahlen mit mindestens p Stellen, davon q hinter dem Dezimalpunkt
158
DDL: Datendefinition mit SQL
Angenähert numerisch
REAL
Gleitpunktzahlen, einfache Genauigkeit
DOUBLE PRECISION
Gleitpunktzahlen, doppelte Genauigkeit
FLOAT(p)
Gleitpunktzahlen, mindestens p Stellen Genauigkeit
Zeichenketten
CHARACTER(n)
Zeichenketten mit genau n Zeichen
CHARACTER VARYING(n)
Zeichenketten mit höchstens n Zeichen
VARCHAR
Synonym zu CHARACTER VARYING
NATIONAL CHARACTER(n)
Zeichenketten mit genau n Zeichen mit nationalen Besonderheiten wie z.B. Zeichensatz, Sortierreihenfolge
NATIONAL CHARACTER
VARYING(n)
Zeichenketten mit höchstens n Zeichen mit nationalen
Besonderheiten
CHARACTER LARGE
OBJECT (n)
Große Textobjekte. Die maximal mögliche Länge ist implementationsabhängig. Zur Spezifikation großer Längen
können die Abkürzungen K (Kilo), M (Mega), G (Giga)
verwendet werden.
CLOB
Synonym zu CHARACTER LARGE OBJECT
Jede Zeichenkette hat eine bestimmte Länge, wobei diese Länge nicht immer die
Anzahl der Bytes sein muss. Bei nationalen Zeichensätzen tritt eine Reihe von Problemen auf, zum Beispiel:
왘 Im Deutschen bilden ä, ö, ü jeweils einen Buchstaben, der aber bei der Sortie-
rung in Namensverzeichnissen jeweils wie ae, oe, ue zu behandeln ist.
왘 Im Spanischen gelten ch und ll (wie auch ñ) jeweils als ein Zeichen, das nach c, l
(bzw. n) einzusortieren ist.
Bitketten
Bitketten dienen in erster Linie als Behälter für Objekte, die nicht vom DBMS interpretiert werden (wie Bilddaten, Zeichnungselemente, Font-Daten). Die Typen BIT
und BIT VARYING sind aus dem Standard entfernt worden. Es gibt nurmehr einen
Typ für große Bitmuster wie beispielsweise Bilder, Töne, Zeichnungen, deren
Bedeutung dem DBMS nicht bekannt ist, die es also als »unstrukturierte Daten«
behandelt.
159
4 Datendefinition in SQL
BINARY LARGE OBJECT
(n)
Binäre Daten mit einer maximalen Länge entsprechend n Zeichen
BLOB(n)
Synonym zu BINARY LARGE OBJECT
Datum und Uhrzeit:
DATE
Kalenderdaten vom Jahr 1 bis zum Jahr 9999
TIME(p)
Uhrzeit in Stunden, Minuten, Sekunden, wobei die Sekunden
noch p Stellen nach dem Komma haben
TIMESTAMP(p)
Datum und Uhrzeit
TIME(p) WITH TIME ZONE
Die Angabe einer Zeitzone ist die Abweichung von der UCT
(Zeitzone von London, früher »GMT« genannt). Wegen der
Sommerzeit kann sie zwischen -11:59 und +13:00 liegen.
MEZ ist UCT +1:00, MESZ = UCT + 2:00.
TIMESTAMP(p) WITH TIME
ZONE
Datum und Uhrzeit mit Zeitzone
INTERVAL YEAR
Datumsdifferenz in Jahren
INTERVAL YEAR TO MONTH
Datumsdifferenz in Jahren und Monaten
INTERVAL DAY
Zeitdifferenz in Tagen
INTERVAL DAY TO HOUR
Zeitdifferenz in Tagen und Stunden
INTERVAL DAY TO
MINUTE
Zeitdifferenz in Tagen, Stunden, Minuten
INTERVAL MINUTE TO
SECONDS (6)
Zeitdifferenz in Minuten und Mikrosekunden
Logischer Datentyp
In der Praxis sind boolesche Variablen unverzichtbar. Jedes Prädikat (WHEREKlausel) ist schließlich ein boolescher Wert. In Programmiersprachen werden boolesche Ausdrücke benutzt, um Verzweigungen zu bearbeiten (IF ... THEN ... ELSE).
Einige, aber längst nicht alle Datenbanksysteme bieten einen solchen Typ für logische Daten bereits an. Umso erstaunlicher ist es, dass es bis 1999 gedauert hat, bis
der Datentyp BOOLEAN in SQL Einzug gehalten hat.
BOOLEAN
160
Wahrheitswerte TRUE und FALSE sowie UNKNOWN
DDL: Datendefinition mit SQL
Leider fehlt bei den Datenbanksystemen häufig der boolesche Datentyp. In diesem
Fall kann man sich notdürftig mit CHAR oder INTEGER behelfen, wobei beispielsweise 0 als FALSE und 1 als TRUE interpretiert wird. Diese Interpretation
sollte dann dokumentiert und durchgehend eingehalten werden. Wir können auf
diese Weise auch eine Domäne mit dem Befehl CREATE DOMAIN boolean definieren.
Die booleschen Operationen sind damit aber in keiner Weise verfügbar.
4.3.3 Operationen mit Datentypen
Mit den Datentypen sind bestimmte erlaubte und sinnvolle Operationen und
Funktionen verbunden. Wir stellen dies hier nur beispielhaft dar und verzichten
auf eine vollständige Aufzählung.
Operationen mit Zahlen
Für numerische Datentypen sind dies zunächst einmal die arithmetischen Operatoren:
+
Addition
-
Subtraktion
*
Multiplikation
/
Division
Weitere mathematische Operationen wie Potenzierung können mit speziellen
Funktionen ermöglicht werden oder sind selbst zu definieren (vgl. Kapitel 7.2).
Bei arithmetischen Operationen gelten die üblichen Hierarchieregeln
왘 Punktrechnung geht vor Strichrechnung.
왘 Bei gleicher Hierarchiestufe wird von links nach rechts gerechnet.
왘 Um davon abzuweichen, sind Klammern zu setzen.
Operationen mit Zeichenketten
Eine ganze Ansammlung von Operatoren und Funktionen für Zeichenketten steht
ebenfalls zur Verfügung. Dazu gehören Funktionen zur Ermittlung der Länge
einer Zeichenkette, zur Extraktion bestimmter Teile, zum Entfernen von Leerzeichen am Anfang und Ende, zur Konvertierung in Großbuchstaben etc. Wir kommen auf diese Funktionen in Kapitel 5 zurück.
Der Operator für die Zeichenverkettung ist:13
||
13 Zwei senkrechte Striche, im ASCII-Code durch den Wert 124 wiedergegeben.
161
4 Datendefinition in SQL
Durch Verkettung von Zeichenketten können zwei oder mehr Spalten virtuell wie
eine ausgegeben werden. Beispielsweise können wir Vornamen und Nachnamen
(unterstellt, diese wären in verschiedenen Spalten enthalten) für ein Adressetikett
so zusammenfügen:
vorname ||' '|| nachname
Operationen mit Datums- und Zeitdaten
Eine Anzahl von Operationen, die sich mit Datums- und Zeitwerten befassen, ist
im Standard definiert. Dazu gehören Differenzen zwischen Datums- und Zeitwerten mit dem Ergebnis eines Intervalls (Tage, Stunden etc.). Auf der anderen Seite
können durch Addition oder Subtraktion von Intervallwerten zu Werten vom Typ
TIMESTAMP neue Werte vom Typ TIMESTAMP gewonnen werden.
Operationen mit booleschen Werten
Für Wahrheitswerte gibt es die üblichen Operatoren AND, OR und NOT. Zum Vergleich von Wahrheitswerten benutzt man nicht das Gleichheitszeichen, sondern
den Operator IS. Das Ergebnis des Vergleichs ist wieder ein boolescher Wert, der
aber nur die Werte TRUE oder FALSE annehmen kann. Wenn wir bei der Artikeltabelle das Attribut kann_wegfallen mit dem Datentyp BOOLEAN definieren,
könnte eine Abfrage beispielsweise die Bedingung enthalten:
WHERE kann_wegfallen IS TRUE
oder auch nur:
WHERE kann_wegfallen
In beiden Fällen steht hinter WHERE ein Wahrheitswert. Im ersten Fall kann nur
TRUE oder FALSE herauskommen, der zweite Ausdruck kann die Werte TRUE,
FALSE oder UNKNOWN annehmen, falls für die Spalte kann_wegfallen Nullmarken erlaubt sind.
Operationen zur Typkonvertierung
Die CAST-Funktion konvertiert skalare Datentypen, sofern der infrage stehende
Wert überhaupt in einen anderen Datentyp konvertiert werden kann. Die allgemeine Syntax ist:
CAST (Skalarer Ausdruck AS [datentyp | domäne])
Beispielsweise kann mit
CAST ('333' AS INTEGER)
die Zeichenfolge ‘333’ in die Zahl 333 umgewandelt werden. Die Zeichenfolge
muss natürlich der Konvention für die Darstellung von Zahlen genügen (vgl.
Abschnitt 4.3.4).
162
DDL: Datendefinition mit SQL
Diese Operation kann auch für Datums- und Uhrzeitwerte angewandt werden;
z.B. ergibt
CAST ('1997-04-01' AS DATE)
das Datum DATE'1997-04-01' (also den 1. April 1997).
Vergleiche von Daten
Die folgende Tabelle listet die Operatoren für Vergleiche auf.
=
gleich
<>
ungleich. In einigen DBMS wird stattdessen der Operator != verwendet.
>
größer als
>=
größer/gleich
<
kleiner
<=
kleiner/gleich
Diese Vergleichsoperatoren können immer angewandt werden, wenn auf beiden
Seiten kompatible Daten stehen. Kompatibel sind zum einen alle Daten desselben
Datentyps, aber darüber hinaus alle numerischen Datentypen und alle Zeichenketten-Datentypen. Somit können natürlich SMALLINT-Größen mit REAL-Größen
verglichen werden oder Zeichenketten der Länge 10 mit Zeichenketten der Länge
5. Der Vergleich verschiedener Datums- und Zeitintervalle ist nicht immer möglich. Ist ein Intervall von 30 Tagen identisch mit einem Monatsintervall? Intervalle
vom Typ YEAR TO MONTH sind beispielsweise nicht mit Intervallen vom Typ
DAY TO SECOND vergleichbar.
Beim Vergleich von Zeichenketten wird diejenige Zeichenkette als »kleiner«
behandelt, deren Anfangszeichen aufgrund der Zeichensatzordnung weiter vorn
im Alphabet stehen, wobei ggf. nationale Besonderheiten (z.B. dass »ß« in der Sortierung äquivalent zu »ss« ist) berücksichtigt werden müssen. 14
4.3.4 Repräsentation der Datentypen
Im Folgenden werden jeweils Beispiele der festgelegten Repräsentation der Daten
für die entsprechenden Datentypen angegeben:
14 Vgl. [DaDa93 Kapitel 19].
163
4 Datendefinition in SQL
INTEGER
123456
–635480
+1
SMALLINT
1234
–6354
+1
NUMERIC(p,q)
DECIMAL(p,q)
1234.56
-1234.67
REAL
DOUBLE PRECISION
FLOAT(p)
1234.56
-1234.67
2.96E+8
3.14E00
-9.8E-3
CHARACTER(n)
CHARACTER VARYING(n)
'Bremerhaven'
'Lübeck'
BIT(n)
BIT VARYING(n)
B'0110'
X'03F4'
DATE
DATE'1995-06-22'
TIME(p)
TIME'09:18:05.23'
TIME'09:15'
TIMESTAMP(p)
TIMESTAMP'1995-06-06 10:00'
TIME(p) WITH TIME ZONE
TIME'09:00+1:00'
TIMESTAMP(p) WITH TIME ZONE
TIMESTAMP'1995-06-06 10:00+1:00'
INTERVAL
INTERVAL
INTERVAL
INTERVAL
INTERVAL
INTERVAL
'3' DAY
'10:30' HOUR TO MINUTE
'10:30' MINUTE TO SECOND
'1-6' YEAR TO MONTH
'3 12:00' DAY TO MINUTE
Die Schreibweise ist noch nicht in allen Systemen systematisch eingeführt. So entfallen insbesondere in einigen Systemen die datenspezifischen Präfixe wie DATE,
TIME, so dass zum Beispiel der 21. Juni 2004 als '2004-06-21' zu schreiben ist. Eine
Unterscheidung zu dem entsprechenden String erfolgt jeweils aus dem Zusammenhang.
164
DDL: Datendefinition mit SQL
4.3.5 CREATE TABLE
Die Anweisung CREATE TABLE dient zur Anlage von Tabellen in einer Datenbank.
Die Struktur der neuen Tabelle wird in Form von Spalten mit jeweils spezifischer
Domäne oder ersatzweise mit Datentyp und Länge festgelegt. Es wird eine leere
Basistabelle erzeugt und gewisse Daten werden in Systemtabellen eingetragen.
Folgende Konsistenzbedingungen können für eine Tabelle festgelegt werden:
왘 Primärschlüssel der Tabelle
왘 Weitere Schlüssel (Kandidatenschlüssel) der Tabelle
왘 Fremdschlüssel mit Bezugstabelle und Verfahrensregeln für die Gewährleis-
tung der referenziellen Integrität
왘 Einschränkungen des Wertebereichs der Spalten
왘 Verbot von Nullmarken in Spalten
왘 Spaltenübergreifende Integritätsbedingungen
왘 Tabellenübergreifende Integritätsbedingungen
Eine CREATE TABLE-Anweisung kann im konkreten Fall beliebig kompliziert
aussehen. Sie setzt sich wie folgt zusammen:
CREATE TABLE tabellenname
(spaltendefinitionsliste
[,tabellenintegritätsregelliste])
Jede Tabelle muss mindestens eine Spalte haben.
spaltendefinition ::=
spaltenname typangabe [vorgabewert]
[spaltenintegritätsregelliste]
Hierbei ist die Typangabe jeweils ein Datentyp oder eine vorher in der Datenbank
definierte Domäne, wie in Abschnitt 4.3.1 eingeführt.
Vorgabewert, Tabellen- und Spaltenintegritätsregeln werden im Verlauf dieses
Kapitels erklärt. Eine bekannte Spaltenintegritätsregel ist die Festlegung NOT NULL.
Der Name der Tabelle muss innerhalb des Schemas eindeutig sein. Innerhalb einer
Tabellendefinition sind die Spaltennamen ebenfalls eindeutig.
Das folgende Beispiel enthält nur eine Spaltendefinitionsliste und keine Tabellenintegritätsregeln. Als einzige Spaltenintegritätsregel wird NOT NULL festgesetzt:
CREATE TABLE
kunden_nr
name
strasse
plz
ort
kunde (
INTEGER NOT NULL,
CHAR(30) NOT NULL,
CHAR(30),
CHAR(5),
CHAR(30) NOT NULL)
165
4 Datendefinition in SQL
Die Integritätsregeln, die nach dem Standard für Spalten und/oder Tabellen in die
Datendefinition eingebracht werden können, werden durch Zusatzklauseln in der
CREATE TABLE-Anweisung formuliert. Diese können in unterschiedlicher Form
in Tabellen- und Spaltenintegritätsregeln verwendet werden. Es sind folgende
Klauseln verfügbar, die in den anschließenden Abschnitten erläutert werden:
tabellenintegritätsregel ::=
check-klausel |
primary_key-klausel |
unique-klausel |
foreign_key-Klausel
Jeder Integritätsregel kann ein Name gegeben werden, was sich bei Verstößen im
Zuge von Dateneingaben oder Änderungen positiv auswirkt, da das DBMS dann
häufig den Namen der verletzten Regel mit ausgibt. Die Syntax dazu:
CONSTRAINT regelname regel
Wir machen in den folgenden Beispielen teilweise davon Gebrauch, verzichten
aber manchmal aus Platzgründen auf die Benennung.
Vorgabewert
Der Vorgabewert in der Spaltendefinition enthält alternativ eine DEFAULT-Klausel, eine IDENTITY-Spezifikation oder eine GENERATION-Klausel. In allen Fällen
geht es darum, Spaltenwerte als Konstante oder als Ergebnis irgendeiner Berechnungsfunktion vorzugeben.
DEFAULT
Die DEFAULT-Klausel in der Spaltendefinition ermöglicht die ausdrückliche
Angabe von Vorgabewerten für den Fall, dass bei der Erfassung oder Änderung
kein Spaltenwert explizit angegeben wird. Ohne diese Klausel ist der Vorgabewert
NULL.
default-klausel ::=
DEFAULT NULL | DEFAULT systemvariable | DEFAULT literal
왘 NULL: Standardmäßig wird eine Nullmarke eingesetzt.
왘 Als Systemvariablen können unter anderem die Folgenden eingesetzt werden:
CURRENT_USER, CURRENT_ROLE
CURRENT_DATE, CURRENT_TIME, CURRENT_TIMESTAMP
왘 literal ist eine explizite Angabe des DEFAULT-Werts. Sie muss der Datentyp-
definition bzw. der Domäne der Spalte entsprechen.
Als Beispiel für eine Anwendung der DEFAULT-Klausel vergeben wir als Vorgabewert für die Zahlungsart eines Kunden den Wert 'N' (für »Nachnahme«). Die Spaltendefinition sieht dann so aus:
zahlung CHAR(1) NOT NULL CONSTRAINT def_zahlung DEFAULT 'N'
166
DDL: Datendefinition mit SQL
IDENTITY-Spezifikation
Neu in SQL:200n ist die Möglichkeit, einer Spalte einen Generator für Sequenznummern zuzuordnen. Dieser bewirkt bei der Neueingabe eines Tupels, dass für
diese Spalte automatisch fortlaufende Werte generiert werden. Ideal ist dies für die
Erzeugung von Schlüsselnummern in Fällen, wo der Schlüssel ein einfaches numerisches Attribut ohne eigene Aussage ist. Einem Attribut kann nur dann eine
IDENTITY-Spezifikation angehängt werden, wenn es auf einem einfachen numerischen Datentyp ohne Nachkommastellen beruht.
Die Klausel lautet in vereinfachter Form:
GENERATED [ ALWAYS | BY DEFAULT ] AS IDENTITY
(START WITH startwert INCREMENT BY inkrement)
Mit den Parametern wird festgelegt, dass die Folge mit dem Wert startwert
beginnt und bei jedem Einfügen eines Tupels in die Tabelle um den Wert von inkrement erhöht wird, wobei inkrement auch negativ sein darf. Weitere Optionen erlauben die Festlegung eines minimalen und maximalen Werts, und ob die Zählung
wieder von vorn beginnen soll, wenn der Maximalwert erreicht worden ist. Letztere Einstellungen sind natürlich für Schlüsselspalten nicht interessant, denn dann
dürfen ja keine Wiederholungen vorkommen.
Bei Sybase Adaptive Server Anywhere wird die Klausel in ähnlicher Form angeboten. Wir könnten beispielsweise für eine Kundennummer automatische Werte
generieren lassen mit:
CREATE TABLE kunde3(
kunden_nr
INTEGER
IDENTITY NOT NULL ,
kname
PersonenName NOT NULL,
CONSTRAINT pk_kunde PRIMARY KEY (kunden_nr)
);
Hier ist aber keine Festlegung von Startwert und Inkrement möglich, das DBMS
fängt bei 1 an und erhöht jedesmal um 1. Beim Einfügen in die Tabelle kann man
dann den Wert für die Kundennummer weglassen, beispielsweise so:
INSERT INTO Kunde3 (kname) VALUES ('Otto');
Eine Alternative zum Erzeugen von Sequenznummern besteht darin, mit dem
Befehl CREATE SEQUENCE einen Generator als eigenes Datenbankobjekt zu erzeugen.
Beispiel:
CREATE SEQUENCE sq_kunde (START WITH 100 INCREMENT BY 1)
Beim Einfügen eines neuen Tupels in die Tabelle wird dann mit
NEXT VALUE FOR sq_kunde
in der Werteliste der nächste Wert aus der Folge abgerufen.15
15 Testen konnten wir dies leider nicht. Eine ähnliche Lösung gibt es bei ORACLE. Dort lautet der
Einfügebefehl unter Zugriff auf den Nummerngenerator:
INSERT INTO kunde3(kunden_nr, name) VALUES (sq_kunde.nextval, 'Otto').
167
4 Datendefinition in SQL
GENERATION-Klausel
SQL sieht vor, dass eine Tabellen berechnete Spalten enthalten darf. Zur Definition dient die GENERATION-Klausel. Wir gehen hier nicht darauf ein und verweisen zum Thema berechnete Spalten auf das Kapitel 6 über Datensichten. Im
Unterschied zu den Datensichten werden aber die Werte berechneter Spalten in
Basistabellen abgespeichert und bei jeder Änderung des Tupels automatisch
aktualisiert.
CHECK-Klausel
Die Anwendung von Domänen anstelle von Typangaben in der Spaltendefinition
wurde im Abschnitt über Domänen bereits erläutert. Die CHECK-Klausel ermöglicht Festlegungen bezüglich erlaubter Spaltenwerte unabhängig von einer Domänendefinition, geht aber darüber insofern hinaus, als auch Bedingungen formulierbar sind, die mehrere Spalten betreffen.
Für die CHECK-Klausel gilt die Syntax:
CHECK (bedingung)
Die Bedingung wird wie in der WHERE-Klausel der SELECT-Anweisung angegeben.
Sie muss sich auf die Spalten der zu erzeugenden Tabelle beziehen. Dabei sind
aber auch Unterabfragen zulässig, die sich auf andere Tabellen beziehen. Im folgenden Beispiel wird die CHECK-Klausel bei der Definition einer Kundentabelle
mehrfach angewandt, um die erlaubten Werte für die Spalten status und zahlung
zu spezifizieren.
CREATE TABLE kunde (
kunden_nr
INTEGER
NOT NULL,
status
CHAR(1)
NOT NULL,
name
CHAR(30) NOT NULL,
strasse
CHAR(30) NOT NULL,
plz
CHAR(5)
NOT NULL,
ort
CHAR(30) NOT NULL,
letzte_bestellung DATE,
letzte_werbeaktion DATE,
zahlungsart
CHAR(1)
NOT NULL,
CONSTRAINT chk_status CHECK (status IN ('S','W','G')),
CONSTRAINT chk_zahlungsart
CHECK (zahlungsart IN ('R','B','N','V','K'))
);
Bei jeder Datenänderung wird sichergestellt, dass die Bedingung nicht den logischen Wert FALSE annehmen kann – der Wert UNKNOWN der dreiwertigen Logik im
Zusammenhang mit Nullmarken ist dagegen zulässig. In dem folgenden Beispiel
ist es also zulässig, dass liefermenge vorübergehend eine Nullmarke enthält – es ist
168
DDL: Datendefinition mit SQL
nicht zulässig, dass die Attribute liefermenge und bestellmenge definierte Werte
haben und der Wert für liefermenge größer ist als der für bestellmenge.
CHECK (liefermenge <= bestellmenge)
Wie wir an folgendem Beispiel sehen, kann die CHECK-Klausel auch direkt an die
Spaltendefinition angefügt werden.
CREATE TABLE kunde (
kunden_nr INTEGER
NOT NULL,
status
CHAR(1)
NOT NULL
CHECK status IN ('S', 'W', 'G'),
...
zahlungsart
CHAR(1)
NOT NULL
CHECK (zahlungsart IN ('R', 'B', 'N', 'V', 'K'))
);
Die NOT NULL-Bedingung könnte auch als CHECK-Klausel formuliert werden,
wir haben im Beispiel aber die übliche Kurzform beibehalten.
Wir sehen an diesem Beispiel, dass der Unterschied zwischen einer Tabellenintegritätsregel und einer Spaltenintegritätsregel hier verschwimmt. Es gibt in diesem
Fall keine Unterschiede – weder in der Formulierung noch in der Bedeutung. Dies
gilt, solange eine CHECK-Klausel sich auf eine einzige Spalte bezieht. Wenn
mehrere Spalten betroffen sind, hat die CHECK-Klausel den Charakter einer Tabellenintegritätsregel und steht separat nach den Spaltendefinitionen.
Primärschlüssel
Der SQL-Standard unterstützt die Primärschlüsseldefinition auf der Ebene der
Tabellenerzeugung.
Jede Relation muss einen Primärschlüssel enthalten. Die PRIMARY KEY-Klausel
ist aber nicht verbindlicher Bestandteil der CREATE TABLE-Anweisung. Die Syntax folgt dem Schema:
PRIMARY KEY (spaltenliste)
Es sind die Attribute anzugeben, die zusammen den Schlüssel bilden. In vielen
Fällen besteht der Schlüssel nur aus einem Attribut.
Zusammen mit den bereits definierten Klauseln könnte die Definition der Kundentabelle so aussehen:16
CREATE TABLE kunde (
kunden_nr
INTEGER
status
CHAR(1)
NOT NULL,
NOT NULL,
16 Wir haben hier der Deutlichkeit halber den Befehl ohne Rückgriff auf Domänen formuliert.
Sonst würden in diesem Befehl keine CHECK-Klauseln auftreten, da diese in den Domänendefinitionen enthalten sind.
169
4 Datendefinition in SQL
name
CHAR(30)
NOT NULL,
strasse
CHAR(30)
NOT NULL,
plz
CHAR(5)
NOT NULL,
ort
CHAR(30)
NOT NULL,
letzte_bestellung DATE,
letzte_Werbeaktion DATE,
zahlungsart
CHAR(1)
NOT NULL DEFAULT 'N',
CONSTRAINT chk_status CHECK (status in ('S','W','G')),
CONSTRAINT chk_zahlungsart
CHECK (zahlungsart in ('R','B','N','V','K'))
CONSTRAINT pk_kunde PRIMARY KEY (kunden_nr)
);
Wenn es sich um einen einspaltigen Primärschlüssel handelt, ist es auch möglich,
das Schlüsselwort PRIMARY KEY als Bestandteil der Spaltendefinition einzutragen.
In unserem Beispiel könnten wir die Formulierung wie folgt abändern:
CREATE TABLE kunde (
kunden_nr INTEGER
...
);
NOT NULL PRIMARY KEY,
Hinter den Schlüsselwörtern PRIMARY KEY entfällt dann die Angabe der Spalte.
Damit wäre die Klausel als Spaltenintegritätsregel formuliert. Dies ändert aber
nichts an der Tatsache, dass ein Primärschlüssel sich immer auf eine ganze Tabelle
bezieht und nicht nur auf die (ggf. einzige) Spalte, aus der er besteht. Wir empfehlen daher, die PRIMARY KEY-Klausel immer nach den Spaltendefinitionen hinzuschreiben.
Die Einbeziehung eines Attributs in den Primärschlüssel setzt voraus, dass für dieses Attribut Nullmarken ausgeschlossen sind. Nach dem Standard kann auf diese
Angabe verzichtet werden – das System setzt diese Bedingung automatisch ein.
UNIQUE-Klausel
Diese Erweiterung der Tabellendefinition dient dazu, Kandidatenschlüssel zu verwalten, also Attribute oder Attributkombinationen, die geeignet sind, ein Tupel
eindeutig zu identifizieren. Der Primärschlüssel stellt davon nur einen Spezialfall
dar. Die Syntax lautet:
unique_klausel ::=
UNIQUE (spaltenliste | VALUE )
Bei einer UNIQUE-Angabe wird nicht verlangt, dass die Definitionen der
zugrunde liegenden Spalten die Klausel NOT NULL enthalten. Es wird dann nicht als
Verstoß gegen die Eindeutigkeit gewertet, wenn der Schlüsselkandidat für eine
Zeile eine Nullmarke hat. Bei mehrspaltigen Schlüsseln wäre sogar jede »eindeutige« Kombination von Nullmarken einmal erlaubt. Wir halten dies für keine gute
170
DDL: Datendefinition mit SQL
Lösung, da hier implizit so getan wird, als sei NULL von jedem anderen Wert zu
unterscheiden. Wenn die Nullmarke bedeutet, »Wert vorhanden, aber nicht bekannt«
(A-Marke), ist diese Unterstellung nicht zu halten.
Auf der anderen Seite ist damit auch festgelegt, dass für eine UNIQUE-Bedingung,
die I-Marken enthalten kann, jeweils nur ein Tupel NULL enthalten kann. So kann
z.B. ein Fahrzeugmotor immer nur in einem Fahrzeug eingebaut sein – oder in keinem, wenn er zur Überholung in der Werkstatt ist –, ein Fall, der durch eine
I-Marke zu kennzeichnen wäre. Eine UNIQUE-Bedingung auf der Fahrzeugnummer führt aber dazu, dass maximal ein Motor jeweils zur Überholung in der Werkstatt sein darf. Dieser Sachverhalt ist also dann anders abzubilden (z.B. indem für
die Beziehungsmenge ist_eingebaut_in eine eigene Relation mit den Attributen
Fahrzeugnummer und Motornummer und ggf. weiteren Attributen gebildet
wird).
Zum Beispiel könnte für die Buchhaltung jedem Kunden eindeutig ein Debitorenkonto zugeordnet sein:
CREATE TABLE KUNDE (
kunden_nr
INTEGER NOT NULL,
,,,
konto_nr
INTEGER NOT NULL,
CONSTRAINT pk_kunde PRIMARY KEY (kunden_nr),
CONSTRAINT uq_kunde UNIQUE (konto_nr)
);
UNIQUE kann bei einspaltigen Kandidatenschlüsseln auch in Kurzform als Bestand-
teil der Spaltendefinition verwendet werden. Mit UNIQUE (VALUE) wird festgelegt, dass die Tupel einer Tabelle eindeutig sein müssen, also je zwei Tupel sich in
mindestens einem Attributwert unterscheiden.17
FOREIGN KEY-Klausel
Die Anforderungen der referenziellen Integrität werden sehr gut unterstützt. Es
soll sichergestellt werden, dass für einen Fremdschlüssel nur solche Werte verwendet werden dürfen, die auch in der Menge der korrespondierenden Primärschlüsselwerte vorkommen.
Beispielsweise soll in einer Tabelle bestellung die Kundennummer kunden_nr als
Fremdschlüssel für die Tabelle kunde vorkommen. Damit kann zu jedem Auftrag
der zugehörige Auftraggeber ermittelt werden. Es muss sichergestellt werden,
dass nur gültige, d.h. in kunde vorhandene Kundennummern in bestellung erfasst
werden können. Dies ermöglicht die FOREIGN KEY-Klausel. Die Syntax der Klausel lautet:
17 Bei Relationen wäre dies ohnehin gegeben, bei Tabellen sind aber mehrere gleiche Tupel möglich (vgl. Kapitel 2.6).
171
4 Datendefinition in SQL
foreign_key-klausel ::=
FOREIGN KEY (spaltenliste)
REFERENCES tabellenname [(spaltenliste)]
[MATCH übereinstimmungstyp]
[ON DELETE änderungsaktion]
[ON UPDATE änderungsaktion]
Die nicht obligatorischen Teilklauseln MATCH sowie ON DELETE und ON UPDATE werden weiter unten gesondert behandelt.
Die Spaltenangabe nach der Angabe der referenzierten Tabelle ist dann erforderlich, wenn sich der Fremdschlüssel nicht auf den Primärschlüssel, sondern auf
einen Kandidatenschlüssel bezieht. Ansonsten kann sie entfallen.
In der Tabelle bestellung enthält das Attribut kunden_nr die Kundennummer, die
auf das gleichnamige Attribut in der Kundentabelle verweist.
CREATE TABLE bestellung (
bestell_nr
INTEGER
NOT NULL,
kunden_nr
INTEGER
NOT NULL,
bestelldatum
DATE
NOT NULL DEFAULT CURRENT DATE,
lieferdatum
DATE,
rechnungsbetrag MONEY,
CONSTRAINT pk_bestellung PRIMARY KEY (bestell_nr),
CONSTRAINT fk_bestellung_kunde
FOREIGN KEY (kunden_Nr) REFERENCES kunde
);
Auch hier ist eine Kurzform möglich, wenn der Fremdschlüssel nur aus einer
Spalte besteht. Die Kurzform lautet hier:
CREATE TABLE bestellung (
bestell_nr
INTEGER
NOT NULL PRIMARY KEY,
kunden_nr
INTEGER
NOT NULL
FOREIGN KEY REFERENCES kunde,
,,,
);
MATCH-Klausel
Mit der Match-Klausel kann festgelegt werden, welcher Grad der Übereinstimmung von Fremdschlüsselwerten mit dem Primär- oder Kandidatenschlüssel der
referenzierten Tabelle verlangt wird. Diese Festlegung ist nur dann von Relevanz,
wenn der Fremdschlüssel aus mehreren Attributen besteht, von denen wenigstens
ein Teil Nullmarken enthalten kann. Grundsätzlich gilt die referenzielle Integrität
immer dann als erfüllt, wenn der gesamte Fremdschlüssel NULL ist. Wenn aber
ein Teil der Attribute eine Nullmarke enthält, sind mehrere Varianten möglich:
übereinstimmungstyp ::= SIMPLE | PARTIAL | FULL
172
DDL: Datendefinition mit SQL
SIMPLE
Mit der Klausel MATCH SIMPLE wird festgelegt, dass die referenzielle Integrität
bereits als erfüllt gilt, wenn eines der Fremdschlüsselattribute NULL ist. Das
bedeutet, die Übereinstimmung des Fremdschlüssels mit einem Schlüssel in der
Vatertabelle wird überhaupt nur dann überprüft, wenn alle Fremdschlüsselattribute einen Wert haben. Diese Regel gilt auch implizit, wenn keine MATCH-Klausel
angegeben wird, und war in bisherigen Versionen des Standards die einzige Möglichkeit.
PARTIAL
Hier wird zugelassen, dass Teile eines Fremdschlüssel NULL-Werte haben dürfen.
Die Übereinstimmung von Fremdschlüssel- und Primär- oder Kandiatenschlüssel
wird im Unterschied zur SIMPLE-Variante überprüft, aber nur für die Attribute,
die einen Wert haben.
FULL
Hier wird generell verlangt, dass entweder alle Fremdschlüsselattribute NULL
sind oder alle einen Wert haben müssen, der dann auf Übereinstimmung mit
Schlüsselwerten in der referenzierten Tabelle überprüft wird. Enthält ein Teil der
Fremdschlüsselattribute eine Nullmarke, gilt die referenzielle Integrität als verletzt.
Wenn bei der Tabellendefinition für alle Fremdschlüsselattribute NOT NULL verlangt
wird – kein Fremdschlüsselattribut darf dann fehlen – ist die Unterscheidung der
Übereinstimmungstypen ohne Relevanz, die MATCH-Klausel ist dann überflüssig.
Aktionsregeln für die referenzielle Integrität
Mit der FOREIGN KEY-Klausel wird erreicht, dass nur gültige Fremdschlüsselwerte erfasst werden können. Damit ist bei »Vater-Sohn-Beziehungen« zwischen
Tabellen die Integrität der abhängigen Tabelle gesichert. Die referenzielle Integrität
kann aber auch durch Änderungen in der Vatertabelle bedroht sein. Dies ist dann
der Fall, wenn dort eine Zeile gelöscht wird, deren Primärschlüsselwert von der
abhängigen Tabelle referenziert wird, oder wenn ein als Fremdschlüsselwert vorkommender Primärschlüsselwert verändert wird.
Der SQL-Standard definiert eine Syntax für Regeln, die bei schreibenden Zugriffen
auf referenzierte Primärschlüsselwerte die Integrität gewährleisten. Darin können
Aktionen festgelegt werden: Die Veränderung kann ganz verboten werden, sie
kann an den Fremdschlüsselwert weitergegeben werden oder dieser kann auf NULL
bzw. den Default-Wert gesetzt werden.
Syntaktisch ist Folgendes definiert:
änderungsaktion ::=
NO ACTION | CASCADE | SET NULL | SET DEFAULT
173
4 Datendefinition in SQL
NO ACTION
Jegliche Änderung an den referenzierten Schlüsselwerten ist untersagt, wenn es
korrespondierende Fremdschlüsselwerte gibt. Diese Regel gilt auch implizit
immer dann, wenn keine Änderungsaktion angegeben wird.18
Wir können also beispielsweise keinen Kunden löschen, zu dem noch Bestellungen
existieren. Aktualisierungen oder Löschungen solcher Primärschlüsselwerte sind
untersagt.
CASCADE
Die per Fremdschlüsselwert korrespondierenden Zeilen in der abhängigen Tabelle
werden entsprechend manipuliert, wenn der referenzierte Schlüsselwert gelöscht
oder geändert wird. Wird also ein Kunde gelöscht, dann verliert man auch seine
Bestellungen.
SET NULL
Korrespondierende Fremdschlüsselwerte werden auf NULL gesetzt, wenn der referenzierte Schlüssel manipuliert wird. Das setzt voraus, dass für die Fremdschlüsselwerte Nullmarken zugelassen sind, was im Beispiel der Kunden und Bestellungen natürlich auszuschließen ist. Es gibt aber solche Fälle: Wird beispielsweise in
einer Tabelle abteilung der Abteilungsleiter durch einen Fremdschlüssel auf die
Tabelle personal dargestellt, so kann dieser vorübergehend eine Nullmarke enthalten. Das bedeutet dann, dass die Abteilung zurzeit keinen Leiter hat.
SET DEFAULT
Alle entsprechenden Fremdschlüsselwerte werden auf den bei der Tabellendefinition mit der DEFAULT-Klausel definierten Standardvorgabewert gesetzt, wenn
der Primärschlüsselwert verändert wird.
Auswahl der passenden Variante
Welche dieser Möglichkeiten infrage kommt, muss nach der jeweiligen Sachlage
entschieden werden. Würde die Option ON DELETE CASCADE bei der Definition der
Bestellungstabelle angewandt, hätte dies zur Folge, dass mit jedem Kunden, der
gelöscht wird, zugleich seine Aufträge verschwinden. Bei ON DELETE SET NULL würden die Aufträge erhalten bleiben, wären aber keinem Kunden mehr zugeordnet.
In diesem Beispiel der Beziehung kunde-bestellung wird man in den meisten Firmen wohl die Variante NO ACTION bevorzugen. Falls in einen Auftrag schon sehr
viel investiert wurde – beispielsweise im Schiffbau –, könnte aber auch bei Ausfall
des Auftraggebers ein Nullsetzen der Kundennummer angezeigt sein, was bedeutet, dass für einen bestehenden Auftrag ein neuer Kunde zu suchen ist. Bei bestellung und position wird in vielen Fällen ein kaskadierendes Verfahren sinnvoll
18 Bei manchen DBMS (z.B. ORACLE, Sybase) wird dies durch RESTRICTED ausgedrückt.
174
DDL: Datendefinition mit SQL
sein: Wird ein Auftrag storniert, entfallen auch alle Positionen. Bei der Definition
der Tabelle position wäre dann Folgendes anzugeben (wir unterstellen diesmal,
dass für die einzelnen Wertebereiche der Attribute Domänen definiert wurden):
CREATE TABLE position (
bestell_nr
Bestell_key
NOT NULL,
artikel_nr
Artikel_key
NOT NULL,
mwst
Prozentsatz,
-- aus Artikeldatei zu übernehmen
bestellmenge
CARDINAL
NOT NULL,
liefermenge
CARDINAL,
gesamtpreis
MONEY,
CHECK (bestellmenge >= 1),
CHECK (liefermenge <= bestellmenge)),
PRIMARY KEY (bestell_nr, artikel_nr),
CONSTRAINT fk_position_bestellung
FOREIGN KEY (bestell_nr)
REFERENCES bestellung
ON UPDATE CASCADE
ON DELETE CASCADE,
CONSTRAINT fk_position_artikel
FOREIGN KEY (artikel_nr)
REFERENCES artikel
);
Die Kurzform, bei der die Fremdschlüsseleigenschaft einer Spalte direkt bei der
Spaltendefinition angegeben wird, lautet hier:
CREATE TABLE position (
bestell_nr
Bestell_key
NOT NULL
FOREIGN KEY REFERENCES bestellung
ON UPDATE CASCADE
ON DELETE CASCADE,
,,,
);
4.3.6 Assertions
Integritätsbedingungen, die mehrere Tabellen betreffen, können nicht immer als
Bestandteil der CREATE TABLE-Anweisung formuliert werden. Solche Einschränkungen werden im Standard als Assertion (»Zusicherung«) bezeichnet. Es gibt
dort auch eine entsprechende Anweisung CREATE ASSERTION mit folgender Syntax:
CREATE ASSERTION assertion_name
CHECK (bedingung) [attributliste]
175
4 Datendefinition in SQL
Es ist jeweils eine logische Bedingung anzugeben, die nicht verletzt werden darf.
Die optionalen Attribute können beschreiben, dass die Assertion verzögert werden
kann (um z.B. eine Bedingung zu formulieren, die Aktionen in mehr als einer
Tabelle erfordert).
Das folgende Beispiel stellt sicher, dass einem Kunden die Zahlungsart 'B' für
»Bankeinzug« nur dann zugewiesen werden kann, wenn in der Datenbank sein
Bankkonto erfasst ist.19
CREATE ASSERTION kunde_zahlart
CHECK (NOT EXISTS (
SELECT * FROM kunde k
WHERE zahlung = 'B'
AND NOT EXISTS (
SELECT * FROM girokonto g
WHERE g.kunden_nr = k.kunden_nr
)))
DEFERRABLE;
Wenn die Anweisung CREATE ASSERTION nicht zur Verfügung steht, wie es bei vielen DBMS noch der Fall ist, muss man unter Umständen zum Hilfsmittel der
Datenbank-Trigger greifen, um eine tabellenübergreifende Integritätsbedingung
zu formulieren.20 Das ist dann zwar eine prozedurale statt einer deklarativen
Lösung, aber immer noch besser, als das Problem in die Anwendungsprogrammierung zu verlegen.
4.3.7 Entfernung von Datenbankobjekten
Sämtliche Datenbankobjekte, die mit irgendeiner Form einer CREATE-Anweisung
angelegt wurden (CREATE TABLE, CREATE DOMAIN etc.), können aus der Datenbank
auch wieder entfernt werden. Dazu stehen Varianten der DROP-Anweisung zur
Verfügung. Dabei ist grundsätzlich zu beachten, dass Datenbankobjekte selbst
auch einer Art referenzieller Integrität unterworfen sind. Tabellen oder Domänen
können ja von anderen Objekten aus referenziert werden.
Die Entfernung einer Datenbanktabelle geschieht beispielsweise mit der DDLAnweisung DROP TABLE. Sofern eine Tabelle an keiner definierten Beziehung teilnimmt und keine Datensichtdefinitionen auf sie Bezug nehmen, wird die Anweisung ohne weiteres ausgeführt. Anders sieht es aus, wenn beispielsweise eine
Fremdschlüsselbeziehung zu der fraglichen Tabelle existiert.
19 Der hier vorgestellte Befehl CREATE ASSERTION konnte bisher nicht getestet werden, da kein
den Autoren zugängliches DBMS ihn unterstützt.
20 Vgl. Kapitel 7.
176
DDL: Datendefinition mit SQL
Wenn beispielsweise eine Tabelle bestellung mit der Integritätsregel
... FOREIGN KEY (kunden_nr) REFERENCES kunde
definiert ist, wird die Anweisung DROP TABLE kunde dann nicht ausgeführt, da
implizit eine Restriktion gilt. Sollen hingegen mit einer Tabelle alle Bezüge auf sie
ebenfalls gelöscht werden, muss dies mit dem Zusatz CASCADE angefordert werden.
Die Anweisung
DROP TABLE kunde CASCADE;
löscht automatisch die obige Integritätsdefinition aus der Tabelle bestellung.
4.3.8 CREATE INDEX
Die Definition von Indexen gehört nicht in die Datendefinitionssprache im engeren Sinne. Indexe dienen dazu, Abfragen an eine Datenbank zu beschleunigen.21
Sie sind aber bei einem echten relationalen Datenbanksystem nicht erforderlich,
um Daten überhaupt zu finden. Die Formulierung von Abfragen ist unabhängig
von der Existenz oder Nichtexistenz von Indexen.22 So wird der Kunde mit
kunden_nr = 103 mit der Anweisung
SELECT * FROM kunde WHERE kunden_nr = 103
gesucht – unabhängig davon, ob ein Index auf kunden_nr existiert oder nicht.23
Bei klassischen Dateiverwaltungssystemen wäre hingegen die Nutzung eines
Index explizit anzufordern. Ein Beispiel im Pseudocode für den Fall, dass ein
Index existiert:
Öffne Kundendatei für lesenden Zugriff über Index kunden_nr
Lies Kundensatz mit Schlüssel kunden_nr = 103
Falls nicht gefunden: Fehlerbehandlung
Falls kein Index existiert, wäre dagegen in etwa wie folgt zu verfahren:
Öffne Kundendatei für sequenziellen lesenden Zugriff
Lies ersten Satz
Solange letzter Lesezugriff erfolgreich und kunden_nr ≠ 103 tue
Lies nächsten Satz
Ende tue
Falls nicht kunden_nr ≠ 103: Fehlerbehandlung
21 Vgl. Kapitel 2.7.
22 Das ändert nichts daran, dass erfahrene Anwendungsentwickler unter Umständen eine von
mehreren äquivalenten Formulierungen einer Abfrage bevorzugen, um den Optimierer »auszutricksen«. Sie riskieren aber, dass beim nächsten Versionswechsel des DBMS der erwünschte
Effekt nicht mehr eintritt.
23 Allerdings können die Antwortzeiten in den beiden Fällen erheblich voneinander abweichen.
177
4 Datendefinition in SQL
Wir führen Indexe hier auf, da sie ein wichtiges Instrument bei der Gestaltung von
Datenbankanwendungen sind und ihre Definition in vielen Fällen zugleich mit der
Definition der Tabellen erfolgt.
Die Syntax der CREATE INDEX-Anweisung ist nicht Gegenstand des SQL-Standards.
Dennoch ähneln sich die verschiedenen SQL-Implementationen in diesem Punkt.
Die Syntax bei ORACLE, Sybase oder DB2 lautet beispielsweise:
CREATE [UNIQUE] INDEX index_name
ON tabellenname (spaltenliste) [ASC | DESC]
Der Zusatz UNIQUE bewirkt, dass für sämtliche Zeilen der Tabelle die Kombination
der Werte der Indexspalten verschieden sein muss. Damit konnten in der Vergangenheit auch solche DBMS indirekt das Primärschlüsselkonzept unterstützen, bei
denen die PRIMARY KEY- und die UNIQUE-Klausel in der CREATE TABLEAnweisung (seit 1989 Bestandteil des SQL-Standards) noch nicht verfügbar waren.
Die Angabe von ASC bzw. DESC bewirkt die aufsteigende bzw. absteigende Sortierung des Index und ist nur wichtig für sortierte Ausgaben von Daten, in denen das
Sortierkriterium mit den Spalten eines Index beginnt.
Zum Beispiel wird mit folgender Anweisung ein aufsteigend sortierter, eindeutiger Index über die Spalte kunden_nr in der Kundentabelle definiert:
CREATE UNIQUE INDEX ix_kunde ON kunde (kunden_nr);
Zu beachten ist, dass Indexe nicht nur die Datenbank schneller machen. Wenn das
DBMS einerseits Abfragen beschleunigt bearbeitet, wird es bei Einfüge- und Änderungsoperationen meist langsamer. Aber auch Abfragen können unter Umständen
durch Indexe verlangsamt werden – ein weites Feld für Experimente!24
4.3.9 Übungsaufgaben
Aufgabe 4.1
einer Datenbank sind die Tabellen angestellte(abtnr, ...) und
abteilung(abtnr, ...) enthalten. In der Anweisung CREATE TABLE angestellte finIn
det sich die Klausel:
FOREIGN KEY abteilung
REFERENCES abteilung(abtnr)
ON UPDATE CASCADE
In abteilungen wird nun ein Primärschlüsselwert geändert, der als Fremdschlüsselwert referenziert wird. Die Nummer einer Abteilung, zu der Angestellte gehören, wird also geändert und die vorherige Abteilungsnummer existiert danach
nicht mehr.
24 Siehe hierzu den Aufsatz: »Kriterien für die Anlage eines Index« [Unte93a].
178
DDL: Datendefinition mit SQL
a) Was passiert aufgrund des oben angegebenen Anweisungsteils in angestellte?
b) Was würde passieren, wenn die obige Anweisung mit der Aktionsregel ON UPDATE SET NULL formuliert worden wäre?
c) Was würde passieren, wenn die obige Anweisung mit der Aktionsregel ON UPDATE NO ACTION formuliert worden wäre?
Aufgabe 4.2
Dozent
Teilnehmer
DozNr
DozName
TnNr
TnName
10
Peters
100
Lück
11
Meier
101
Hinz
12
Otten
102
Kunz
Seminar
SemNr
Thema
Datum
Preis
DozNr
DozName
1001
DatStru
13.12.2003
250
10
Peters
1002
SysAnal
15.10.2003
350
12
Otten
Seminarteilnehmer
SemNr
TnNr
TnName
Bezahlt
1001
100
Lück
J
1001
102
Kunz
N
1002
101
Hinz
J
Die oben dargestellte Datenstruktur ist in einer SQL-Datenbank zu realisieren. Die
Primärschlüssel sind jeweils unterstrichen. Zuvor sind aber noch ein paar kleine
Probleme zu klären.
a) Welche Normalformen sind verletzt (vgl. Kapitel 3.4)?
b) Wie sind die entsprechenden Tabellen zu modifizieren, damit die erste bis dritte
Normalform erfüllt wird?
c) Definieren Sie Domänen mit der CREATE DOMAIN-Anweisung.
d) Definieren Sie die Tabellen mit der CREATE TABLE-Anweisung.
179
Herunterladen