Datenbanksysteme: Unterschied zwischen den Versionen
(Explanation added.) |
(EMailAddr changed from NOT NULL to NULL.) |
||
Zeile 62: | Zeile 62: | ||
LoginName CHAR(64) NOT NULL, | LoginName CHAR(64) NOT NULL, | ||
PasswdHash CHAR(255) NOT NULL, | PasswdHash CHAR(255) NOT NULL, | ||
− | EMailAddr CHAR(255) | + | EMailAddr CHAR(255) NULL, |
LastName CHAR(255) NULL, | LastName CHAR(255) NULL, | ||
FirstName CHAR(255) NULL, | FirstName CHAR(255) NULL, | ||
Zeile 96: | Zeile 96: | ||
LoginName CHAR(64) NOT NULL, | LoginName CHAR(64) NOT NULL, | ||
PasswdHash CHAR(255) NOT NULL, | PasswdHash CHAR(255) NOT NULL, | ||
− | EMailAddr CHAR(255) | + | EMailAddr CHAR(255) NULL, |
LastName CHAR(255) NULL, | LastName CHAR(255) NULL, | ||
FirstName CHAR(255) NULL, | FirstName CHAR(255) NULL, | ||
Zeile 117: | Zeile 117: | ||
PRIMARY KEY (PostID) | PRIMARY KEY (PostID) | ||
); | ); | ||
+ | |||
=== Eindeutige Werte === | === Eindeutige Werte === | ||
Zeile 153: | Zeile 154: | ||
Im Gegensatz zu Primärschlüsseln sind in Spalten, die in einem UNIQUE-Constraint vorkommen, NULL-Werte grundsätzlich erlaubt, sofern diese nicht mittels NOT NULL in der Spaltendefinition ausgeschlossen wurden. Im Beispiel muss die E-Mail-Adresse also nicht angegeben | Im Gegensatz zu Primärschlüsseln sind in Spalten, die in einem UNIQUE-Constraint vorkommen, NULL-Werte grundsätzlich erlaubt, sofern diese nicht mittels NOT NULL in der Spaltendefinition ausgeschlossen wurden. Im Beispiel muss die E-Mail-Adresse also nicht angegeben | ||
werden, jedoch dürfen unter den eingetragenen Werten in der Spalte EMailAddr keine mehrfach auftreten. | werden, jedoch dürfen unter den eingetragenen Werten in der Spalte EMailAddr keine mehrfach auftreten. | ||
+ | |||
=== Fremdschlüssel === | === Fremdschlüssel === | ||
Zeile 203: | Zeile 205: | ||
Das Beispiel zeigt, dass sich ein Fremdschlüssel auch auf einen Schlüssel in derselben Tabelle beziehen kann. Auf diese Weise lassen sich hierarchische Strukturen (Baumstrukturen) in SQL mühelos abbilden. | Das Beispiel zeigt, dass sich ein Fremdschlüssel auch auf einen Schlüssel in derselben Tabelle beziehen kann. Auf diese Weise lassen sich hierarchische Strukturen (Baumstrukturen) in SQL mühelos abbilden. | ||
+ | |||
=== Weitere Bedingungen === | === Weitere Bedingungen === | ||
Zeile 211: | Zeile 214: | ||
( | ( | ||
PostID INTEGER NOT NULL, | PostID INTEGER NOT NULL, | ||
+ | Category INTEGER NOT NULL, | ||
Author INTEGER NULL, | Author INTEGER NULL, | ||
− | |||
Title VARCHAR(512) NOT NULL, | Title VARCHAR(512) NOT NULL, | ||
Content TEXT NOT NULL, | Content TEXT NOT NULL, | ||
Zeile 220: | Zeile 223: | ||
PRIMARY KEY (PostID), | PRIMARY KEY (PostID), | ||
+ | FOREIGN KEY (Category) | ||
+ | REFERENCES Categories (CategoryID) | ||
+ | ON UPDATE RESTRICT | ||
+ | ON DELETE CASCADE, | ||
+ | |||
FOREIGN KEY (Author) | FOREIGN KEY (Author) | ||
REFERENCES Users (UserID) | REFERENCES Users (UserID) | ||
Zeile 225: | Zeile 233: | ||
ON DELETE SET NULL, | ON DELETE SET NULL, | ||
− | FOREIGN KEY ( | + | FOREIGN KEY (Parent) |
− | REFERENCES | + | REFERENCES Posts (PostID) |
ON UPDATE RESTRICT | ON UPDATE RESTRICT | ||
ON DELETE CASCADE, | ON DELETE CASCADE, |
Version vom 25. September 2019, 21:06 Uhr
Große Datenmengen, wie sie beispielsweise in einem Social Network oder Online-Shop anfallen, werden üblicherweise als Datenbanksystem (database system, DBS) verwaltet. Dazu benötigt man ein Programm, das man als Datenbankmanagementsystem (database management system, DBMS) bezeichnet. Ein DBMS kann eine oder mehrere Datenbanken betreiben. Eine Datenbank (database, DB) wiederum besteht aus dem Schema (schema), das die Struktur der zu speichernden Daten beschreibt, und den eigentlichen Daten (data).
Es gibt viele verschiedene Arten von Datenbanksysteme. Wir werden hier zunächst nur relationale Datenbanksysteme thematisieren.
Die Structured Query Language (SQL) ist eine standardisierte Sprache zum Bedienen von DBMS. Sie ist heute sehr weit verbreitet und wird von den meisten DBMS unterstützt. Die zahlreichen SQL-Befehle kann man grob wie folgt einteilen:
- Data Definition Language (DDL) -- Festlegen des Datenbankschemas
- Data Manipulation Language (DML) -- Arbeiten mit dem Datenbestand
- Data Query Language (DQL) -- Abfragen (SELECT)
- Befehle zur Pflege des Datenbestandes (INSERT, UPDATE, DELETE)
- Transaction Control Language (TCL) -- Arbeiten mit Transaktionen
- Data Control Language (DCL) -- Festlegen von Zugriffsrechten
Inhaltsverzeichnis
Festlegen des Datenbankschemas
Definieren von Spalten
Beispiel: Web-Forum
CREATE TABLE Categories ( CategoryID INTEGER, Title CHAR(255), Description VARCHAR(4096) );
CREATE TABLE Users ( UserID INTEGER, LoginName CHAR(64), PasswdHash CHAR(255), EMailAddr CHAR(255), LastName CHAR(255), FirstName CHAR(255), BirthDate DATE );
CREATE TABLE Posts ( PostID INTEGER, Category INTEGER, Author INTEGER, Parent INTEGER, Title VARCHAR(512), Content TEXT, CreatedOn TIMESTAMP, EditedOn TIMESTAMP );
Pflichtfelder
CREATE TABLE Categories ( CategoryID INTEGER NOT NULL, Title CHAR(255) NOT NULL, Description VARCHAR(4096) NULL );
CREATE TABLE Users ( UserID INTEGER NOT NULL, LoginName CHAR(64) NOT NULL, PasswdHash CHAR(255) NOT NULL, EMailAddr CHAR(255) NULL, LastName CHAR(255) NULL, FirstName CHAR(255) NULL, BirthDate DATE NULL );
CREATE TABLE Posts ( PostID INTEGER NOT NULL, Category INTEGER NOT NULL, Author INTEGER NULL, Parent INTEGER NULL, Title VARCHAR(512) NOT NULL, Content TEXT NOT NULL, CreatedOn TIMESTAMP NOT NULL, EditedOn TIMESTAMP NULL );
Primärschlüssel
CREATE TABLE Categories ( CategoryID INTEGER NOT NULL, Title CHAR(255) NOT NULL, Description VARCHAR(4096) NULL, PRIMARY KEY (CategoryID) );
CREATE TABLE Users ( UserID INTEGER NOT NULL, LoginName CHAR(64) NOT NULL, PasswdHash CHAR(255) NOT NULL, EMailAddr CHAR(255) NULL, LastName CHAR(255) NULL, FirstName CHAR(255) NULL, BirthDate DATE NULL, PRIMARY KEY (UserID) );
CREATE TABLE Posts ( PostID INTEGER NOT NULL, Category INTEGER NOT NULL, Author INTEGER NULL, Parent INTEGER NULL, Title VARCHAR(512) NOT NULL, Content TEXT NOT NULL, CreatedOn TIMESTAMP NOT NULL, EditedOn TIMESTAMP NULL, PRIMARY KEY (PostID) );
Eindeutige Werte
Während eine SQL-Tabelle nur einen Primärschlüssel haben darf, können (zusätzlich) beliebig viele UNIQUE-Constraints definiert werden. Diese sorgen ebenso wie Primärschlüssel dafür, dass die Werte in der oder den entsprechenden Spalten eindeutig sind.
Gibt es in einer Tabelle mehrere Schlüsselkandidaten, dann sollte einer davon, gegebenenfalls willkürlich, als Primärschlüssel ausgewählt werden. Für alle anderen Schlüsselkandidaten sollte ein UNIQUE-Constraint formuliert werden.
CREATE TABLE Categories ( CategoryID INTEGER NOT NULL, Title CHAR(255) NOT NULL, Description VARCHAR(4096) NULL, PRIMARY KEY (CategoryID), UNIQUE (Title) );
CREATE TABLE Users ( UserID INTEGER NOT NULL, LoginName CHAR(64) NOT NULL, PasswdHash CHAR(255) NOT NULL, EMailAddr CHAR(255) NULL, LastName CHAR(255) NULL, FirstName CHAR(255) NULL, BirthDate DATE NULL, PRIMARY KEY (UserID), UNIQUE (LoginName), UNIQUE (EMailAddr) );
Im Gegensatz zu Primärschlüsseln sind in Spalten, die in einem UNIQUE-Constraint vorkommen, NULL-Werte grundsätzlich erlaubt, sofern diese nicht mittels NOT NULL in der Spaltendefinition ausgeschlossen wurden. Im Beispiel muss die E-Mail-Adresse also nicht angegeben werden, jedoch dürfen unter den eingetragenen Werten in der Spalte EMailAddr keine mehrfach auftreten.
Fremdschlüssel
Häufig beziehen sich die Daten in einer Tabelle auf Daten in einer anderen Tabelle. Um die referenzielle Integrität der Daten bei derartigen Verweisen unter allen Umständen sicherstellen zu können, bietet SQL die Möglichkeit, sogenannte Fremdschlüssel zu definieren. Dabei muss sich ein FOREIGN KEY immer auf einen PRIMARY KEY oder ein UNIQUE-Constraint in der anderen Tabelle beziehen. Fremdschlüssel müssen in der untergeordneten Tabelle eingetragen werden.
Eins-zu-eins-Beziehungen sowie Eins-zu-viele-Beziehungen im Datenmodell können mit Hilfe von Fremdschlüsseln direkt in SQL implementiert werden. Für Viele-zu-viele-Beziehungen wird eine separate Tabelle benötigt, in der die Paare gespeichert werden. In SQL kann man bei der Definition eines Fremdschlüssels mittels der Klauseln ON UPDATE und ON DELETE angeben, was mit den Zeilen in der untergeordneten Tabelle passieren soll, wenn ein Primärschlüssel in der übergeordneten Tabelle geändert oder gelöscht wird. Dabei gibt es jeweils folgende Möglichkeiten:
- NO ACTION bedeutet, wie der Name schon sagt, dass beim Ändern oder Löschen eines Primärschlüssels keine besondere Maßnahme ergriffen wird. Falls dieser Schlüssel in der untergeordneten Tabelle vorkommt, dann schlägt der entsprechende SQL-Befehl fehl, falls nach Ausführung aller Trigger die referenzielle Integrität verletzt wäre.
- RESTRICT lässt das Ändern oder Löschen eines Primärschlüssels, der bereits von einem Fremdschlüssel referenziert wird, gar nicht zu, auch dann nicht, wenn die referenzielle Integrität durch einen oder mehrere Trigger wiederhergestellt würde.
- SET NULL gibt an, dass alle Fremdschlüssel auf NULL gesetzt werden sollen, wenn der entsprechende Primärschlüssel geändert oder gelöscht wird. Diese Option kann natürlich nur verwendet werden, wenn in der oder den Fremdschlüssel-Spalten NULL-Werte erlaubt sind.
- SET DEFAULT bewirkt, dass die Werte in der oder den Fremdschlüssel-Spalten auf ihre Default-Werte zurückgesetzt werden, wenn der entsprechende Primärschlüssel geändert oder gelöscht wird.
- CASCADE sorgt dafür, dass beim Ändern eines Primärschlüssels alle betroffenen Fremdschlüssel in oder untergeordneten Tabelle ebenfalls geändert werden. Beim Löschen einer Zeile in der übergeordneten Tabelle werden alle Zeilen in der untergeordneten
Tabelle, die per Fremdschlüssel auf diese Zeile verweisen, ebenfalls gelöscht. Leider sind nicht alle Optionen in allen DBMS (korrekt) implementiert. Im Zweifel kommt man nicht umhin, die Dokumentation zu bemühen, um sich Klarheit darüber zu verschaffen, welche Möglichkeiten beim Definieren von Fremdschlüsseln vorhanden sind.
Bei der Auswahl geeigneter Optionen kann man sich an folgenden Faustregeln orientieren: (1) Für natürliche Primärschlüssel wählt man bei allen Fremdschlüsseln, die sich darauf beziehen, ON UPDATE CASCADE, um die referenzielle Integrität auch beim Ändern von Daten zu wahren. Bei künstlichen Primärschlüsseln kann man ON UPDATE RESTRICT verwenden, da es keinen Grund gibt, diese jemals ändern zu wollen. Sollte man doch in diese Versuchung kommen, dann handelt es sich vermutlich gar nicht wirklich um künstliche Schlüssel, sondern sie beinhalten doch auf subtile Weise eine Semantik. (2) Bei einer Komposition im Datenmodell verwendet man ON DELETE CASCADE, bei einer Aggregation je nach Anwendungskontext eine der anderen Optionen.
CREATE TABLE Posts ( PostID INTEGER NOT NULL, Category INTEGER NOT NULL, Author INTEGER NULL, Parent INTEGER NULL, Title VARCHAR(512) NOT NULL, Content TEXT NOT NULL, CreatedOn TIMESTAMP NOT NULL, EditedOn TIMESTAMP NULL, PRIMARY KEY (PostID), FOREIGN KEY (Category) REFERENCES Categories (CategoryID) ON UPDATE RESTRICT ON DELETE CASCADE, FOREIGN KEY (Author) REFERENCES Users (UserID) ON UPDATE RESTRICT ON DELETE SET NULL, FOREIGN KEY (Parent) REFERENCES Posts (PostID) ON UPDATE RESTRICT ON DELETE CASCADE );
Das Beispiel zeigt, dass sich ein Fremdschlüssel auch auf einen Schlüssel in derselben Tabelle beziehen kann. Auf diese Weise lassen sich hierarchische Strukturen (Baumstrukturen) in SQL mühelos abbilden.
Weitere Bedingungen
Mittels der Festlegung von Datentypen sowie den Angabe NOT NULL, PRIMARY KEY, UNIQUE und FOREIGN KEY lassen sich schon viele Integritätsbedingungen für eine Datenbank spezifizieren. Darüber hinaus gibt es aber meist weitere Bedingungen, denen die Daten genügen müssen. Mit Hilfe von CHECK-Constraints lassen sich nahezu beliebig komplexe Einschränkungen für bestimmte Werte definieren. Diese können sich auf eine Spalte in einer Tabelle, mehrere Spalten innerhalb einer Tabelle oder sogar auf mehrere Tabellen beziehen. So können CHECK-Constraints auch Abfragen beinhalten. Auf diese Weise könnte beispielsweise ein INTEGER-Wert in einer Spalte auf die Anzahl der Zeilen in einer anderen Tabelle beschränkt werden, die einer bestimmten Bedingung genügen. Man muss sich aber im Klaren darüber sein, dass diese Abfrage dann bei jedem INSERT- und UPDATE-Befehl ausgeführt wird. Umfangreiche CHECKs können selbst das performanteste DBMS irgendwann einmal in die Knie zwingen. Daher sollte man diese mit Augenmaß einsetzen.
CREATE TABLE Posts ( PostID INTEGER NOT NULL, Category INTEGER NOT NULL, Author INTEGER NULL, Title VARCHAR(512) NOT NULL, Content TEXT NOT NULL, CreatedOn TIMESTAMP NOT NULL, EditedOn TIMESTAMP NULL, PRIMARY KEY (PostID), FOREIGN KEY (Category) REFERENCES Categories (CategoryID) ON UPDATE RESTRICT ON DELETE CASCADE,
FOREIGN KEY (Author) REFERENCES Users (UserID) ON UPDATE RESTRICT ON DELETE SET NULL, FOREIGN KEY (Parent) REFERENCES Posts (PostID) ON UPDATE RESTRICT ON DELETE CASCADE, CHECK (CreatedOn < EditedOn) );