Fachkonzept - Strukturen anlegen
Nach der Modellierung der Anforderungen (z.B. als E/R-Schema) wird ein konzeptionelles Modell in ein relationales Schema verwandelt; d.h. die notwendigen Tabellen werden definiert. Für einen Teil der Anforderungen der Fahrschul-Miniwelt könnte das z.B. so aussehen:
Erkennbar sind die Attribute der Tabellen mit ihren Datentypen
sowie die Beziehung zwischen der Fahrstunde-Tabelle und der Schueler-Tabelle.
Um diese Struktur in der SQL-Datenbank zu erzeugen, kann man Werkzeuge wie z.B. phpMyAdmin verwenden.
Diese nutzen aber intern auch nur SQL-Befehle, die zur DDL - Data Definition Language gehören.
CREATE TABLE
können neue Tabellen in einer Datenbank angelegt werden. Damit wird nur die Struktur einer Tabelle festgelegt - es werden noch keine Daten abgespeichert.
Entsprechend erlaubt der Befehl
DROP TABLE
das Löschen
einer Tabelle (mit allen Daten darin). Der folgende Ausschnitt eines Python-Programms benutzt DDL-Befehle, um die oben gezeigten Tabellen zu erzeugen:
[...]
SQLBefehle = """
CREATE TABLE IF NOT EXISTS schueler (
SNR integer NOT NULL,
Vorname varchar(30),
Name varchar(50) NOT NULL,
PRIMARY KEY (SNR)
);
CREATE TABLE IF NOT EXISTS fahrstunde (
SNR integer,
Datum date,
Zeit time,
PRIMARY KEY (SNR, Datum),
FOREIGN KEY (SNR)
REFERENCES Schueler(SNR)
);
"""
cursor = con.cursor()
try:
for einzelCursor in cursor.execute(SQLBefehle, multi=True):
print(einzelCursor._executed.decode('UTF-8'))
except mysql.connector.Error as err:
print("Fehler bei der SQL-Ausführung: %s" % (err))
[...]
Der Befehl CREATE TABLE
ist dabei sehr einfach zu lesen und erschließt sich fast
von selbst; ein paar Besonderheiten sollen aber am Beispiel erklärt werden:
Befehl | Bedeutung |
---|---|
SNR integer NOT NULL | definiert ein Attribut namens SNR vom Typ integer (also eine ganze Zahl).
Dieses Attribut darf nicht leer bleiben (NOT NULL ) |
Vorname varchar(30) | das Attribut Vorname ist ein string; varchar(30) steht für eine Zeichenkette
(variable character), die maximal 30 Zeichen lang sein darf. |
PRIMARY KEY (SNR) | ist eine Bedingung (engl. Constraint) an die Tabelle: SNR ist der Primärschlüssel |
FOREIGN KEY (SNR) REFERENCES schueler(SNR) | ist eine weitere Bedingung: SNR ist ein Fremdschlüssel, der sich auf das Attribut
SNR in der Tabelle schueler bezieht. |
Leider ist SQL an vielen Stellen nicht ganz genormt - nur ein Teil ist in allen relationalen Datenbanksystemen
gleich. So ist auch der Zusatz IF NOT EXISTS
nicht im "Standard"-SQL vorhanden; er verhindert
eine Fehlermeldung, falls die Tabelle schon existiert.
Auch die Datentypen unterscheiden sich stark zwischen den Datenbanksystemen. Nur einige gehören zum SQL-Standard, wie z.B. die oben verwendeten. Übersicht der standardisierten Datentypen:
Datentyp | Namen in SQL |
---|---|
varchar(n) | Ein string (text) mit der maximalen Länge n. Werden längere Texte eingefügt, so werden diese abgeschnitten. |
integer | Eine ganze Zahl. Welche maximale bzw. minimale Zahl wirklich gespeichert werden kann, ist vom Datenbanksystem abhängig. |
real | Speicherung einer Kommazahl - die Genauigkeit hängt wieder vom Datenbanksystem ab. Alternative ist float(n), wobei n für die Anzahl an Nachkommastellen steht. |
date | Speichert ein Datum (ohne Zeit). Die Darstellung ist in der Regel dem amerikanischen angelehnt (also '2016-06-30' für den 30. Juni 2016) |
time | Angabe einer Uhrzeit |
blob(n) | Ein "binäres" Objekt mit maximal n Bytes Länge. Wird z.B. für das Speichern von Bildern, etc. verwendet. Die Art der Speicherung differiert zwischen den verschiedenen Datenbanksystemen. |
Exkurs - Verarbeiten von SQL-Skripten in Python
Im Gegensatz zu den letzten Kapiteln wird im Beispiel nicht nur ein SQL-Befehl abgearbeitet, sondern gleich eine Abfolge von Befehlen - ein sogenanntes SQL-Skript. Die einzelnen SQL-Befehle werden dort mit einem Strichpunkt voneinander getrennt.
Damit der Python-Connector nicht nur den ersten Befehl abarbeitet, sondern das gesamte Skript, muss die Verarbeitung des Cursors angepasst werden:
for einzelCursor in cursor.execute(SQLBefehle, multi=True):
print(einzelCursor._executed.decode('UTF-8'))
Die execute
-Methode führt nacheinander alle SQL-Befehle aus und gibt jeweils einen
"normalen" Cursor für diesen Befehl zurück. Bei DDL-Befehlen wird (anders als beim SELECT
) keine
Rückgabe erwartet, weshalb mit diesen Einzelcursor hier auch nicht weiter gearbeitet wird. Stattdessen wird mit
print(...)
nur der jeweilige SQL-Befehl ausgegeben.