Datenbanksysteme: Unterschied zwischen den Versionen

Aus Informatik interaktiv
(EMailAddr changed from NOT NULL to NULL.)
(Explanation added.)
Zeile 49: Zeile 49:
  
 
=== Pflichtfelder ===
 
=== Pflichtfelder ===
 +
 +
Jeder Datentyp in SQL verfügt über die spezielle Konstante NULL, die angibt, dass der entsprechende Wert nicht vorhanden ist. Für solche fehlenden Werte gibt es vielfältige Gründe: Beispielsweise kann sich um einen optionalen Eintrag in einem Formular handeln, den der Benutzer nicht ausgefüllt hat, der Wert kann (zur Zeit noch) unbekannt oder im konkreten Fall ohne Belang sein.
 +
 +
Die Konstante NULL darf keinesfalls mit der Zahl 0 oder der leeren Zeichenfolge ’’ verwechselt werden. Dies ist für »Datenbank-Neulinge« gewöhnungsbedürftig, da die allermeisten Programmiersprachen nicht über einen solchen »Luxus« verfügen, so dass die NULL-Semantik gegebenenfalls mit Hilfe einer separaten booleschen Variable realisiert werden muss.
 +
 +
Beim Anlegen einer Tabelle ist es möglich, NULL-Werte in einer Spalte zu verbieten. Dazu müssen dem Datentyp die Schlüsselwörter NOT NULL folgen. Ohne diese Angabe sind NULL-Werte in der entsprechenden Spalte erlaubt. Dies kann auch ausdrücklich durch NULL
 +
gekennzeichnet werden, was zwecks besserer Lesbarkeit durchaus empfehlenswert ist.
  
 
   CREATE TABLE Categories
 
   CREATE TABLE Categories
Zeile 79: Zeile 86:
 
     EditedOn    TIMESTAMP      NULL
 
     EditedOn    TIMESTAMP      NULL
 
   );
 
   );
 +
 +
In obigem Beispiel der Tabelle Users müssen die Spalten UserID, LoginName und PasswdHash in allen Zeilen ausgefüllt werden. Man beachte, dass ohne weitere Vorkehrungen die leere Zeichenfolge immer noch zulässig ist, was für den Login-Namen im Anwendungskontext sicher nicht wünschenswert wäre. Alle anderen Spalten (mit den personenbezogenen Daten) dürfen auch unausgefüllt bleiben, also NULL-Werte enthalten.
  
 
=== Primärschlüssel ===
 
=== Primärschlüssel ===

Version vom 25. September 2019, 21:11 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


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

Jeder Datentyp in SQL verfügt über die spezielle Konstante NULL, die angibt, dass der entsprechende Wert nicht vorhanden ist. Für solche fehlenden Werte gibt es vielfältige Gründe: Beispielsweise kann sich um einen optionalen Eintrag in einem Formular handeln, den der Benutzer nicht ausgefüllt hat, der Wert kann (zur Zeit noch) unbekannt oder im konkreten Fall ohne Belang sein.

Die Konstante NULL darf keinesfalls mit der Zahl 0 oder der leeren Zeichenfolge ’’ verwechselt werden. Dies ist für »Datenbank-Neulinge« gewöhnungsbedürftig, da die allermeisten Programmiersprachen nicht über einen solchen »Luxus« verfügen, so dass die NULL-Semantik gegebenenfalls mit Hilfe einer separaten booleschen Variable realisiert werden muss.

Beim Anlegen einer Tabelle ist es möglich, NULL-Werte in einer Spalte zu verbieten. Dazu müssen dem Datentyp die Schlüsselwörter NOT NULL folgen. Ohne diese Angabe sind NULL-Werte in der entsprechenden Spalte erlaubt. Dies kann auch ausdrücklich durch NULL gekennzeichnet werden, was zwecks besserer Lesbarkeit durchaus empfehlenswert ist.

 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
 );

In obigem Beispiel der Tabelle Users müssen die Spalten UserID, LoginName und PasswdHash in allen Zeilen ausgefüllt werden. Man beachte, dass ohne weitere Vorkehrungen die leere Zeichenfolge immer noch zulässig ist, was für den Login-Namen im Anwendungskontext sicher nicht wünschenswert wäre. Alle anderen Spalten (mit den personenbezogenen Daten) dürfen auch unausgefüllt bleiben, also NULL-Werte enthalten.

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)
 );

Abfragen

Pflege des Datenbestandes

Einfügen von Datensätzen

Ändern von Datensätzen

Löschen von Datensätzen