Datenbanken mit  SQL Einführung in die relationale Algebra PostgreSQL, MariaDB und SQLite V 21.07.30

 

 

Einführung

Begriffe

Daten
Digitalisierte, formalisierte und kodierte Informationen, welche durch Interpretieren in einem Bedeutungskontext wiedergewonnen werden können. Mittels Verknüpfungen zwischen Daten kann zusätzliches Wissen geschöpft werden.
Metadaten
Strukturierte Daten, welche Informationen über Merkmale anderer Daten enthalten.
Datensatz
Gruppe von inhaltlich zusammenhängenden Daten (Datenfeldern).
Persistenz
Fähigkeit, Daten oder logische Verbindungen über lange Zeit – insbesondere über einen Programmabbruch hinaus – bereitzuhalten. Zum Erhalt der ~ wird ein nichtflüchtiges Speichermedium benötigt; wobei auch Dateisysteme sowie durch Protokolle gesicherte bidirektionale und transaktionsorientierte Datenübertragungen als nichtflüchtige Medien betrachtet werden können.
Redundanz
Eine Informationseinheit ist dann redundant, wenn diese ohne Informationsverlust weggelassen werden kann. Durch das Vermeiden redundanter Information ist die Eindeutigkeit (Konsistenz) der Datensätze gewährleistet. Jedoch können bewusst eingeführte Redundanzen, um weniger Tabellen miteinander verknüpfen zu müssen (Kartesisches Produkt), zu sichtlich schnelleren Abfragen führen.
Konsistenz
Widerspruchsfreiheit von Daten.
Inkonsistenz einer DB kann entweder durch fehlerhafte Dateneingaben bzw Transaktionen, oder aufgrund unplanmäßiger Redundanzen entstehen.
Datenbank
Formalisierte, strukturierte und kodierte Darstellung logisch zusammenhängender Daten.
Sammlung von Daten und zugehörigen Beschreibungsinformationen (Metadaten), welche einen Ausschnitt aus der realen Welt (Miniwelt) beschreiben, in einem logischen Zusammenhang stehen und persistent sowie formal strukturiert sind. ~ werden für einen bestimmten Zweck entworfen und implementiert.
Datenbankverwaltung (Datenbankmanagementsystem – DBMS)
Sammlung von anwendungsunabhängigen Programmen (Softwaresystem) zum Erstellen und Verwalten einer Datenbank. Darüber hinaus werden Datenverwaltungssysteme genutzt, um durch Verknüpfen von Daten neues Wissen zu erschließen.
Die ~ muss ein effizientes, zuverlässiges, aber auch sicheres System zum Speichern von Datenbeständen und den darauf – zumeist parallel – stattfindenden Zugriffen bieten.
Die ~ muss Mechanismen zur Datenintegrität (Konsistenz), zum Schutz vor unerwünschten Zugriffen (Authentifizierung / Autorisierung), sowie vorbeugend gegen Datenverlust und Inkonsistenz bei Fehlern (Ausfallsicherheit) bereithalten.
Referenzielle Integrität
Beziehungen zwischen den Tabellen, verwirklicht über Primär- und Fremdschlüssel, um die Konsistenz und Integrität der Datenbank sicherzustellen.
Konkret wird die ~ mittels Regeln – entweder in Form von Constraints oder Triggers – gewährleistet, welche die Bedingungen vorgeben, unter denen ein Datensatz eingefügt, verändert oder gelöscht werden darf.
Transaktion – Durchführung
Folge von Operationen auf einen Datenbestand, welche nach fehlerfreier und vollständiger Ausführung einen konsistenten Datenbankzustand hinterlassen.
Datenarten
Strukturierte Daten
Datensatz ist begründet auf einer Definition der einzelnen Datenfelder (formalisierte Struktur – Datenmodell); zB Arbeitsblätter, Tabellen.
Halbstrukturierte Daten
Enthalten implizite Strukturinformationen; zB CSV, XML, Graphen.
Unstrukturierte Daten
Ohne bewusst geschaffene Struktur; zB Texte, Bilder, Videos

Coddsche Regeln

Das relationale Datenbankmodell beruht auf dem mathematischen Konzept der Relation und wurde von dem Mathematiker Edgar F. Codd entwickelt. Alle relevanten Informationen einer Datenbank werden darin in Relationen abgelegt. Edgar F. Codd definierte neun Anforderungen, die sog Coddschen Regeln, welche für einen zuverlässigen und effizienten Datenbankbetrieb notwendig sowie hinreichend sind:

  1. Integration

    Daten müssen in einer einheitlichen Struktur ohne Redundanz abgelegt werden.

  2. Operationen

    In einer Datenbank müssen Daten gespeichert, geändert und gesucht werden können.

  3. Katalog

    Über eine spezielle Struktur (Verzeichnis) müssen Informationen bereitgestellt werden, welche die Daten näher beschreiben (Metadaten).

  4. Benutzersichten

    Unterschiedliche Anwendungen erfordern unterschiedliche Sichten auf den Datenbestand.

  5. Integritätssicherung

    Die Korrektheit des Datenbankinhalts muss durch Regeln gewährleistet werden, welche jeder Datenbankeintrag zu erfüllen hat.

  6. Datenschutz

    Nur berechtigte Benutzer und Programme dürfen Zugriff auf die Datenbank haben.

  7. Transaktionskontrolle

    Mehrere Anweisungen sind zu einer einzigen Transaktion zu bündeln, damit diese als eine funktionale Einheit vollständig und fehlerfrei ausgeführt werden können.

  8. Synchronisation

    Parallel ausgeführte Transaktionen müssen den gleichen Datenbankzustand hervorrufen wie irgendeine serielle Ausführung der Transaktionen.

  9. Datensicherung

    Die Datenbankverwaltung muss nach einem Systemfehler in der Lage sein, den letzten konsistenten Datenbankzustand mittels automatischer Verfahren wiederherzustellen.

 

DBMS
Komponenten eines Datenbankmanagementsystems

Konsistenzmodell: AKID (en ACID)

Eigenschaften von Transaktionen

Atomarität – Abgeschlossenheit (en Atomicity)
Eine Transaktion ist eine Folge von Datenbank-Operationen, welche entweder vollständig und fehlerfrei als Ganzes oder gar nicht auszuführen sind. Sollte eine Transaktion nicht vollständig abschließbar sein, erfolgt ein Zurücknehmen aller ausgeführten Anweisungen bis zum ursprünglich gültigen Zustand (en roll back – Zurückrollen).
Konsistenzerhaltung (en Consistency)
Eine Transaktion muss nach Abschluss einen widerspruchsfreien Datenbank­zustand hint­er­lassen, indem alle Integritäts­be­dingungen eingehalten sind. Ist das nicht möglich, oder tritt ein Fehler auf, wird die gesamte Transaktion zurückgenommen und der ursprünglich Zustand wiederhergestellt.
Isolation – Abgrenzung
Die Datenbankverwaltung muss gewährleisten, dass sich Transaktionen verschiedener Anwender oder Prozesse nicht gegenseitig beeinflussen. In der Regel werden benötigte Daten für eine Transaktion vor­über­geh­end gesperrt, damit andere nebenläufige Transaktionen keinen Einfluss ausüben können.
Dauerhaftigkeit (en Durability)
Nach Abschluss einer Transaktion liegen die Daten dauerhaft gespeichert vor. Auch darf nach einem Systemfehler – bspw bei Ausfall des Hauptspeichers – kein Datenverlust auftreten. Dauerhaftigkeit kann durch das Schreiben eines Transaktionslogs sichergestellt werden, um nach einem Systemausfall fehlende oder unvollständige Operationen nachzuholen.

Sperrverfahren schränken die Nebenläufigkeit ein und begünstigen Blockierungen, weshalb in vielen Datenbanksystemen das verwendete Isolationsverfahren einstellbar ist, um bestimmte eigentlich unerwünschte Effekte für eine höhere Nebenläufigkeit zuzulassen.

Verarbeitungsarten

Datenbanken arbeiten entweder transaktional (überweisenden) oder analytisch (untersuchend).

Online Transaction Processing Data Base / OLTP-DB
Online-Transaktionsverarbeitung / Echtzeit-Transaktionsverarbeitung
Benutzungsparadigma von Datenbanksystemen und Geschäftsanwendungen, bei dem die Verarbeitung von Transaktionen unmittelbar sowie prompt, also ohne nennenswerte Zeitverzögerung, stattfindet. Gegenstück ist die Stapelerarbeitung, bei welcher alle Geschäftsvorfälle gesammelt und zu einem späteren Zeitpunkt durchlaufen werden. Neben dem schnellen Verarbeiten kurzer Abfragen liegt das Hauptaugenmerk auf der Wahrung von Datenintegrität in Umgebungen mit mehreren – zumeist parallelen – Zugriffen, sowie auf eine an der Anzahl der Transaktionen pro Sekunde gemessenen Effektivität. Demnach speichern OLTP-Datenbanken insbesondere detaillierte und aktuelle Daten nach dem Entitätsmodell (in der Regel 3NF).
Architektur und Arbeitsweise ist darauf ausgelegt, je Sekunde tausende Operationen (Einfügen, Ändern, Löschen von Daten) umzusetzen.
Online Analytical Processing / OLAP-DB
analytische Datenverarbeitung / Echtzeitdatenanalyse
Benutzungsparadigma zum Speichern von aggregierten historischen Daten, auf welche zumeist nur lesend zugegriffen wird. OLAP-Datenbanken zeichnet sich durch ein verhältnismäßig geringes Transaktionsvolumen aus und kommen vor allem im Bereich der Datenförderung (en data mining) zum Einsatz, um insbesondere komplexe Anfragen (Aggregate, Verknüpfungen, analytische Funktionen, statistische Berechnungen) in Sekunden bzw Minuten zu realisieren.
Im Gegensatz zu OLTP-Datenbanken steht die Durchführung komplexer Analysevorhaben im Vordergrund, welche ein sehr hohes Datenaufkommen verursachen. Das Ziel ist, durch multidimensionale Betrachtung dieser Daten (OLAP-Würfel) ein entscheidungsunterstützendes Analyseergebnis zu gewinnen.
Gegenüberstellung von OLTP und OLAP
MerkmalOLTPOLAP
Grundschematransaktionsorientiertanalyse- / themenorientiert
Zweckoperative Systeme (Administrations- und Dispositionssysteme)Data-Warehouse-Systeme
NutzerAdministration,
Sachbearbeiter
Entscheidungs- / Führungskräfte
Datenstrukturzweidimensional,
anwendungsbezogen
multidimensional,
subjektbezogen
Dateninhaltdetaillierte und unverdichtete Einzeldatenverdichtete und abgeleitete Daten
Zwecktransaktionale Konsistenzerhaltungzeitbasierte Versionierung
Datenaktualitätaktuelle Geschäftsdatenhistorische Verlaufsdaten
Aktualisierungdurch laufende Geschäftsvorfälleperiodische Datenaktualisierung (Schnappschuss)
Zugriffsformlesend / schreibend / löschendlesend / verdichtend
Zugriffsmustervorhersehbar, repetitivad hoc, heuristisch
Zugriffshäufigkeithochmittel bis niedrig
Transaktionsdauerkurze Lese- / Schreiboperationenlange Lesetransaktionen

Drei-Schichten-Architektur

Die ~, auch Drei-Schema-Architektur oder Drei-Ebenen-Architektur genannt, beschreibt die grundlegende Trennung verschiedener Bereiche einer Datenbank mit dem Ziel, den Benutzer einer Datenbank vor nachteiligen Auswirkungen bei Änderungen in der Datenbankstruktur zu schützen.

Jede Schicht verfolgt einen bestimmten Zweck, um die zu speichernden Daten entgegenzunehmen, strukturiert abzulegen und dem Anwender oder dem Anwendungssystems wieder zur Verfügung zu stellen.

Für den Informationsaustausch zwischen den Schichten werden Transformationsregeln definiert. Dieser Aufbau ist entscheidend für das Einhalten der Anforderungen eines Datenbanksystems.

3-Schichten-Architektur
Drei-Schichten-Architektur Im Allgemeinen beschreibt eine Drei-Schichten-Architektur ein Modell, bei welchem die Software in drei grundlegende und stark voneinander entkoppelte Bereiche gegliedert ist.
Externe Ebene
Für Benutzer und Anwendungen individuell bereitgestellte Sichten auf den Datenbestand wie Formulare, Suchmasken, Listen, aber auch Programmierschnittstellen.
Konzeptionelle Ebene
Beschreibt, welche Daten von der Datenbank erfasst werden, sowie deren Beziehungen zueinander (Nachbilden von Realwelt-Zusammenhängen). Entwurfsziel ist eine vollständige und redundanzfreie Darstellung aller zu speichernden Informationen, einhergehend mit einer Normalisierung des relationalen Datenbankschemas.
Interne Ebene
Auch physische Ebene, welche die Speicherung der Daten und Zugriffspfade umfasst. Entwurfsziel ist ein effizienter Zugriff auf die gespeicherten Informationen.

Die Vorteile des Drei-Ebenen-Modells liegen in der

Relationenalgebra

Die Relationenalgebra – auch relationale Algebra – bildet das mathematisch-theoretische Fundament von Abfragesprachen wie SQL. Das Ziel ist eine Logik, in welcher sich Abfragen formulieren lassen, ohne die Art und Weise vorgeben zu müssen (→ deklarative Sprache).

Operationen

Gegenstand der relationalen Algebra sind auf Relationen angewandte Operationen wie das Filtern, Verknüpfen und Aggregieren, wobei im Ergebnisse neue Relationen entstehen.

Anmerkungen
Selektion

Die Operation σX wählt jene Teilmenge einer Relation aus, welche die Bedingung X erfüllt:

σA=1{(A,B),(1,3),(1,4),(2,5)}={(A,B),(1,3),(1,4)}
Projektion

Die Projektion π entfernt Attribute (Spalten) aus der Eingaberelation:

πA,C{(A,B,C),(1,4,7),(2,5,8),(3,6,9)}={(A,C),(1,7),(2,8),(3,9)}

Der Mengencharakter hat zur folge, dass gleiche Tupeln nicht vorkommen:

πB{(A,B),(1,4),(2,5),(3,4)}={B,4,5}

Auch sind Umbenennungen des Tabellenkopfs ausdrückbar:

πBA{(A,),}={(B,),}
Kartesisches Produkt

Das kartesische Produkt A × B zweier Mengen A und B ist definiert als die Menge aller geordneten Paare (a , b), mit a als Element aus A und b als Element aus B:

{(A,B),(1,2),(3,4)}{C,6,8)}={(A,B,C),(1,2,6),(1,2,8),(3,4,6),(3,4,8)}
Verbund / Join

Ein Join ist die Kombination aus kartesischem Produkt und Selektion:

MA=BN=σA=B(MN)

Der Verbund kombiniert Tupel, wobei Datensätze ohne Verbundpartner entfernt werden.

SQL

Zweck Abfragesprache
Grundparadigma deklarativ / logisch
Nebenparadigma prozedural
Syntax ALGOL-artig
Speicherverwaltung automatisch
Typsystem stark, statisch
Übersetzungsmodell interpretierend
Dateiendungen SQL
Ersterscheinungsjahr 1974
Erfinder IBM: Donald D. Chamberlin, Raymond F. Boyce
Herausgeber ISO/IEC
Vorläufer Prolog > Datalog
Abkömmlinge LINQ, OQL, …
Standardisierungen ANSI / FIPS: SQL-{86, 89, 92}
ISO: SQL {1999, 2003, 2006, 2008, 2011, 2016, 2019}
freie Umsetzungen mariaDB, MySQL, PostgreSQL, SQLite
proprietäre — IBM Db2, MS SQL Server, Oracle
freie DBMS DBeaver, Emma, Firebird, MySQL Workbench, phpMyAdmin
proprietäre — IBM Db2, Microsoft SQL Server, Oracle Database Server

Die nachfolgende Zusammenfassung von SQL – ausgeschrieben Structured Query Language – beschränkt sich auf die Implementierungen PostgreSQLMySQL bzw. MariaDB sowie SQLite. Da aber PostgreSQL deutlich über die zuletzt genannten Datenbanksysteme hinausgeht, ist dem ein eigenes Kapitel gewidmet.

Teilsprachen

Die Data Query Language wird häufig auch als Teil der DML gezählt.

Literale & Datentypen

SQL kennt vier Arten von literalen Repräsentationen:

character string 'Hello, World!'
bit string b'1011000'
x'5FA7CA1'
exact numeric 58
+31
3.14159
-3234
hexadecimal numeric 0x2AB85F
approximate numeric 6E6
+0.725E
36.86E-13
-323E-3

Manche Datenbanken erlauben auch doppelte Anführungszeichen. Von deren Gebrauch ist aber abzuraten, um möglichst kompatibel zum Standard zu bleiben.

MySQL / MariaDB

Bezüglich der Datentypen sind MySQL und MariaDB noch weitestgehend kompatibel zueinander.

Numerische Datentypen
tinyint* / int1* [-128, 127]
boolean {0, false, 1 true}
smallint* / int2* [-32768, 32768]
mediumint* / int3* [-8388608, 8388607]
integer* / int* / int4* [-2147483648, 2147483647]
bigint* / int8* [-1 · 263, 263 – 1]
decimal(N[,DECIMALS])* präzise Festkommazahl
float(N[,DECIMALS])* Gleitkommazahl mit einfacherer Genauigkeit
real / double(N[,DECIMALS])* — doppelte Genauigkeit
bit Bitfeld

Für decimal sind noch die Synonyme dec, numeric und fixed bekannt.

Alle mit einem Sternchen * gekennzeichneten Zahlentypen sind zusätzlich spezifizierbar:

DATATYPE [signed | unsigned | zerofill]

DATATYPE [unsigned zerofill | zerofill unsigned]

Zeichentypen
char(n) fixierte Länge im Bereich [0, 255]
→ rechtsseitig mit Leerzeichen aufgefüllt
varchar(n) variabel mit [0, 65532] als mögliche Obergrenzen
tiny text maximal 255
text maximal 65535
mediumtext maximal 16777215
json / longtext maximal 4294967295 / 4GB
inet6 IPv6 Adressen
enum('VALUE', …) beschränkt Auswahl auf einen der vorgegebenen Werte
maximal 65535 Vorgaben zulässig
set('VALUE', …) erlaubt Teilmenge der aufgelisteten Werte, einschließlich ''
Trennung von mehreren Werten mittels Komma ,
maximal 64 Werte zulässig
tinyblob binäres Objekt mit maximal 255 Bytes
blob binäres Objekt mit maximal 65535 Bytes
mediumblob binäres Objekt mit maximal 16777215 Bytes
longblob binäres Objekt mit maximal 4294967295 Bytes / 4GB

SQL unterscheidet nicht zwischen Zeichenketten und einem einzelnen Symbol. Folglich darf char nicht mit dem gleichnamigen numerischen Datentyp aus C oder anderen Sprachen verwechselt werden.

Bei Mengen ist zu beachten, dass deren Werte kommagetrennt in einer Zeichenkette übergeben und angezeigt werden (einschließlich Leerzeichen), wobei die Reihenfolge der zulässigen Elemente – festgehalten in der Typdefinition – stets eingehalten wird:

Empfehlung
Datum- und Zeitangaben
date YYYY-MM-DD
time HH-MM-SS[.PRECISION]
datetime YYYY-MM-DD HH-MM-SS[.PRECISION]
timestamp YYYY-MM-DD HH-MM-SS[.PRECISION] + Zeitzone
year YYYY

Im Gegensatz zu datetime erfasst timestamp automatisch den Zeitpunkt des Tabelleneintrags.

SQLite

Im Gegensatz zu anderen Implementierungen weist SQLite keine strenge, statische Typisierung vor. Stattdessen gehören Daten einem der folgenden Speicherklassen (en storage classes) an:

null ungültiger Wert
integer vorzeichenbehaftete Ganzzahl
real Gleitkommazahl
text Zeichenkette
blob Binärobjekt

Speicherklassen verallgemeinern gleichartige Datentypen. So werden Zahlen im Format des passenden bitmäßig beschränkten Typen abgelegt, aber beim Verarbeiten als eine vorzeichenbehaftete 64-Bit Ganzzahl gelesen.

Abfragen

Eine Abfrage umfasst zumindest eine Auswahl von Spalten oder einen verarbeitbaren Ausdruck, ggf ergänzt um zusätzlich Klauseln:

Aliase und Redundanzen

Aggregatfunktionen

Aggregatfunktionen f(COLUMN) sind deterministische Funktionen, welche aus einer Menge von Spaltenwerten einen neuen Einzelwert berechnen. Zusammen mit group by COLUMN ist eine Aggregatfunktion auf jede Gruppe von Datensätzen anwendbar.

Bedingungen in Abhängigkeit von Aggregatfunktionen können nicht in der WHERE-Klausel stehen, sondern müssen im HAVING-Block erfolgen.

Mit Ausnahme von count() ignorieren Aggregatfunktionen nichtige Werte (NULL).

 Erläuterung
avgDurchschnittswert einer numerischen Spalte
countAnzahl aller ausgewählten Datensätzen, deren Wert nicht NULL ist
maxhöchster Wert
minniedrigster Wert
sumSumme einer numerischen Spalte

Unterabfragen

en subquery

Unterabfragen sind innere Abfragen (Verschachtelungen), welche in den Klauseln select, from und where erscheinen können, sowie in den Anweisungen select, insert, delete und update.

Eine Unterabfrage dient dem Zweck, Daten zurückzugeben, welche in der Hauptabfrage zum Formulieren von Bedingungen benötigt werden.

Weitere Anmerkungen zu Unterabfragen
Korrelierte Unterabfrage

en correlated subquery

Unterabfrage, welche auf Werte einer äußeren Abfrage zurückgreift:

Derartige Verschachtelungen sollten vermieden werden, da die Unterabfrage jeweils für jeden Datensatz der äußeren Abfrage ausgewertet wird und damit die Geschwindigkeit übermäßig beeinträchtigt.

Abgleichen und Sortieren

Muster

Muster (en pattern) sind Zeichenketten mit den folgenden Platzhaltern:

 BedeutungBeispiel
%kein, ein oder beliebig viele Einzelzeichen'a%n'
_einzelnes Zeichen'_n%'

Für komplexere Muster stehen in MySQL / Mariadb reguläre Ausdrücke bereit:

Suchen in Mengen

Die Funktion find_in_set liefert die Position eines Elements zurück bzw. den tatsächlich gespeicherten Wert:

Zu beachten ist, dass alles zwischen den Kommas zum Namen gehören und mit abgeglichen wird, auch Leerzeichen!

Bei Spalten vom Typ einer Menge

Sortieren

Liegt keine Angabe zur Reihenfolge vor, wird asc (aufsteigend) angenommen.

Redundanzvermeidung

Mit distinct werden nur die ersten Datensätze des jeweiligen Spaltenwerts angezeigt.

Sichten

Eine Sicht (en view) ist eine unter einem eigenen Namen gespeicherte und wie eine gewöhnliche Tabelle verwendbare SQL-Abfrage (→ virtuelle Tabelle):

Sichten vereinfachen vor allem den Zugriff auf stark normalisierte Datenbanken.

Operatoren

 SymbolBedeutung
Arithmetik+ - * / %Plus, Minus, …, Modulo
Bitmanipulation& | ^UND, ODER, XODER
Vergleiche= > < >= <= <>gleich, größer, …, ungleich
Zuweisungen+= -= /= %= &= ^= |=Kombinierungen
Konkatenation||nur in SQLite und PostgreSQL

Logische Operatoren

Die logische Operatoren not, and und or (nicht ausschließendes Oder) liefern entweder true oder false zurück und werden in der WHERE oder HAVING-Klausel verwendet:

in

Kurzform für mehrfache ODER-Verknüpfungen

between

Als Grenzen sind Ausdrücke wie Zahlen, Text oder Datumsangaben einsetzbar.

any /some

gibt true zurück, wenn einer der Unterabfragewerte die Bedingung erfüllt.

Der Ausdruck … = any (…) ist gleichwertig zu … in (…).

all

gibt true zurück, wenn alle Unterabfragewerte die Bedingung erfüllen

exists

gibt true zurück, wenn mindestens ein Datensatz in der Unterabfrage existiert

Mengenoperationen

Mit Mengenoperationen lassen sich die Ergebnisse von zwei oder mehr Abfragen bzw Ausdrücken zusammenfassen: EXPR OP EXPR

OperatorErgebnis
unionVereinigung
union allVereinigung zur Multimenge
intersectSchnittmenge
exceptRest / Differenzmenge

Relationale Verbünde / Joins

en joins

Ein relationaler Verbund verknüpft mehrere Tabellen zu einer Ergebnistabelle entsprechend etwaiger Vorbedingungen.

Übersicht
Schlüsselwörter Erläuterung
[cross] joinkartesische ProduktJeder Datensatz der einen Tabelle wird mit jedem Datensatz der anderen kombiniert.
[inner] joininnerer VerbundKombination von Datensätzen unter Verbundbedingungen wie Gleichheit – oder andere Vergleichsoperationen.
left [outer] joinlinksseitiger VerbundUmfasst alle Datensätze der linken Tabelle (links von join), auch wenn die rechte Tabelle keinen korrespondierenden Datensatz bietet; die fehlenden Werte werden mit null aufgefüllt.
right [outer] joinrechtsseitiger VerbundWie linksseitiger Verbund, nur mit dem Unterschied, dass die Datensätze der rechten Tabelle ggf. ergänzt werden.
full [outer] joinäußerer VollverbundVereinigungsmenge der Ergebnisse des links- und rechtsseitigen Verbundes.
Syntax
Innerer Verbund

Ein innerer Verbund kann auf unterschiedliche Weise geschehen:

Syntax  
natural joinNatürlicher Verbund: Verknüpfung der Datensätze, deren Werte bei gleichem Attributnamen übereinstimmen. 
join … using (COLUMNS)Ausdrückliche Angabe der Attribute, über welche die Verknüpfung erfolgen soll. 
join … on T1.C COMPARE T2.CVerbund von Tabellen, bei denen die Bezeichnungen der zu vergleichenden Attribute nicht übereinstimmen oder bei dem ein anderer Operator als = verwendet wird. 

Natürliche Verbünde sollten vermieden werden, da unter Umständen ungewollte bzw falsche Verknüpfungen entstehen.

Verbund mit sich selbst

Ein Self-Join ist ein Verbund, bei dem eine Tabelle ihre Zeilen mit sich selbst verknüpft, was vor allem dann der Fall ist, wenn ein Fremdschlüssel vorliegt, welcher auf den Primärschlüssel der eigenen Tabelle verweist.

Im Gegensatz zu den anderen Verbundarten muss immer mit Aliassen gearbeitet werden, um trotz des gleichen Tabellennamens unterscheiden zu können:

Datenbankerstellung

Die wichtigsten Befehle zum Erstellen oder Verwerfen von Datenbankobjekten werden mit create bzw. drop eingeleitet:

Beschränkungen

en constraints

Beschränkungen werden vorgenommen, um einen bestimmten Wertebereich von Daten festzulegen. Dies stellt die Genauigkeit und Zuverlässigkeit der Daten in der Tabelle sicher. Wenn eine Verletzung zwischen der Einschränkung und einer Datenmanipulation vorliegt, wird die Aktion abgebrochen.

Einschränkungen können auf Spalten- oder Tabellenebene erfolgen. Einschränkungen auf Spaltenebene gelten für eine Spalte, während Einschränkungen auf Tabellenebene für die gesamte Tabelle verbindlich sind.

Folgende Einschränkungen werden häufig in SQL verwendet:

 stell sicher, dass
auto_incrementeine ganzzahlige Spalte autonom u. fortlaufend Schlüssel erzeugt
not nulleine Spalte keine NULL-Werte vorweist
uniquealle Werte in einer Spalte unterschiedlich (einzigartig) sind
primary keyjeder Datensatz (Zeile) einer Tabelle eindeutig identifiziert werden kann: Kombination aus not null und unique
foreign keyder Wert mit dem eines aus einer anderen Tabelle übereinstimmt: referenzierter Wert muss unique oder primary key sein
checkalle Werte in einer Spalte eine bestimmte Bedingung erfüllen
defaultzumindest ein Standardwert für eine Spalte vorliegt
indexDatensätze besonders schnell abgerufen werden können

In Spalten mit auto_increment ist 0 als Primärschlüssel nicht zulässig und wird bei einem INSERT genauso wie NULL übergangen. Ferner darf eine Tabelle das Attribut auto_increment nur einmal vorweisen.

Die Beschränkung auto_increment ist nur in MySQL / MariaDB verfügbar. Jedoch erfüllt in PostgreSQL der Datentyp serial den gleichen Zweck.

Check-Constraints schlagen nicht fehl, wenn ein Wert null ist, sondern werten zu unbekannt aus, womit eine Zeile dennoch akzeptiert wird.

Syntax

Empfohlen wird, Einschränkungen stets einen innerhalb der Datenbank eindeutigen Namen mittels constraint NAME zu geben:

Gibt der Programmierer keinen Namen vor, autogeneriert die Datenbank bei Auftreten von Verletzungen eigene Bezeichnungen, welcher aber nicht verständlich sind. Zudem erleichtert die Benennung von Constraints ganz erheblich spätere Tabellenänderungen.

Namenskonvention
ConstraintAffix
Primary KeyPK
Alternate KeyAK
Foreign KeyFK
IndeXIX
ChecKCK
DeFaultDF
UniQueUQ

Nachträgliches Ändern von Tabellen

Mit dem ALTER-Befehl lassen sich Tabellen nachträglich abändern:

Es sind beliebige Constraints nachträglich hinzufügbar. Eine praktische Anwendung sind wechselseitige (en mutual) Beziehungen zwischen Tabellen, wo erst nach Erstellung der zweiten Tabelle eine Referenz auf diese in der ersten hinzugefügt werden kann.

Einfügen, Ändern und Löschen von Daten

SQL umfasst drei fundamentale Befehle für die Manipulation von Datenbankeinträgen:

Sollen alle Datensätze einer Tabelle gelöscht werden, bietet sich truncate an:

Trigger

Ein Trigger ist eine gespeicherte Prozedur in der Datenbank, welche automatisch aufgerufen wird, wenn ein bestimmtes Ereignis (en event) wie insert, update oder delete auftritt.

MySQL / MariaDB

Für Trigger gelten die folgenden Einschränkungen.

SQLite

SQLite unterstützt die folgenden Trigger:

PostgreSQL

 

Mit seinen zahlreichen Features und langjährigen Stabilität zeichnet sich PostgreSQL als ernstzunehmende sowie professionelle Alternative aus.

Datentypen

Im Gegensatz zu anderen relationalen Datenbanksystemen hält sich PostgreSQL streng an den Standard, sodass bestimmte Datentypen wie tinyint nicht existieren. Dafür trumpft PostgreSQL umso mehr mit einem deutlich leistungsstärkeren Typsystem auf, welches den Programmierer befähigt, eigene Datentypen zu definieren, sodass die Integrität der Datensätze nicht nur durch Relationen gewährleisten werden kann.

Offizielle Dokumentation: https://www.postgresql.org/docs/13/datatype.html

Die offizielle Dokumentation offenbart, dass PostgreSQL noch viele weitere Datentypen unterstützt, u. A. für geometrische Objekte, Netzwerkadressen und Dateiformate wie JSON und XML.

Umwandeln von Typen

PostgreSQL unterstützt den Standard-SQL-Typ boolean mit mehreren literalen Repräsentationen,

true 't' 'yes' 'on' 1
false 'f' 'no' 'off' 0

 

wobei ohne Kontxt und abgesehen von true bzw. false stets der Typ mit angegeben werden muss:

select 'on' :: boolean;

Der zweifache Doppelpunkt :: wird als Cast-Operator bezeichnet und stellt lediglich eine  Kurzschreibweise für cast(EXPR as TYPE) dar.

Zu Beachten ist, dass boolean bis zu drei Zustände abbilden kann: true, false und null.

Numerische Datentypen

NameByteWertebereich
smallint2[-32768, 32767]
integer / int4[-214748364, 2147483647]
bigint8[263, 263 – 1]
decimal / numericvarmax. 131072 Vorkommastellen u. 16383 Nach—
money8[-92233720368547758.08, 92233720368547758.07]
real4Genauigkeit von 6 Nachkommastellen
double precision8Genauigkeit von 15 Nachkommastellen
smallserial2[1, 32767]
serial4[1, 2147483647]
bigserial8[1, 9223372036854775807]

Zwischen decimal und numeric besteht faktisch kein Unterschied. Ferner unterscheidet PostgreSQL nicht zwischen vorzeichenlose und vorzeichenbehaftete Ganzzahlen, da dies der SQL-Standard auch nicht verlangt.

Die seriellen Typen sind für künstliche Schlüssel vorgesehen, wobei serial gleichwertig zu integer NOT NULL DEFAULT nextval('table_name_id_seq') ist. Jedoch vorkonfiguriert PostgreSQL serielle Typen nicht automatisch als unique.

Zeichentypen

NameBeschreibung
textbeliebig lang
character varying(n) / varchar(n)variable Größe mit Maximum
character(n) / char(n)fixiert und mit Leerzeichen aufgefüllt

Die Größe n beschreibt die Zahl an Einzelzeichen und nicht die Höchstgrenze in Byte.

Alle drei Zeichentypen sind intern als variable length array implementiert, was zur Folge hat, dass char – im Gegensatz zu anderen Datenbanksystemen – sogar weniger effizient ist, da aufgrund des Auffüllens mit Leerzeichen unnötig mehr Speicherplatz belegt wird.

Bedingt durch den Wegwahl von Extraprüfungen ist text am performantesten und zu bevorzugen.

Zu beachten ist, dass Indexe auf maximal 2712 Byte je Zeile beschränkt sind, sodass bei indexierten Textspalten ohne Höchstgrenzen – ob über varchar oder einen Constraint realisiert – die Gefahr von Fehlern besteht.

Datum- und Zeitangaben

NameByteBeschreibungRes.
timestamp [(p)]8Tag + Uhrzeit1 µs
timestamp [(p)] with time zone8Tag + Uhrzeit + Zeitzone1 µs
date4Tag1 d
time [(p)]8Uhrzeit1 µs
time [(p)] with time zone12Uhrzeit + Zeitzone1 µs
interval [FIELDS] [(p)]16Zeitraum1 µs

Über den Wert p lässt sich die Genauigkeit der Sekunden von 6 (voreingestellt) auf 0 reduzieren.

Der Intervalltyp hat eine zusätzliche Option, um mittels

die Menge der gespeicherten Felder einzuschränken.

Datums- und Zeitangaben werden in jeglichem gültigen Format akzeptiert:

Verarbeiten von Datumsangaben

Neben der dem SQL-Standard entsprechenden Syntax mittels extract stellt Postgres auch eine Funktion date_part() bereit, um einzelne Werte aus einer Datumsangabe herauszulösen:

Tatsächlich wird im Hintergrund der standardkonforme Ausdruck nach date_part() übersetzt, sodass beide Varianten völlig gleichwertig sind.

Datenfelder / Arrays

In PostgreSQL kann eine Spalte nicht nur einelementig sein, sondern mehrere Werte enthalten, ohne die erste Normalform zu verletzten:

Darüber hinaus sind sogar mehrdimensionale Datenfelder definierbar, ohne die Länge im Voraus fixieren zu müssen.

Literale Datenfelder lassen sich auf zwei Arten angeben: Entweder als speziell formatierte Zeichenketten oder über die array constructor syntax, eingeleitet mit dem Schlüsselwort array und umschlossen von eckigen Klammern.

Ferner stehen zahlreiche Funktionen und Operatoren für die verarbeitung von Arrays bereit:

 BedeutungBeispielErgebnis
=gleich[1.1]::int[] = [1]t
<>ungleich[1,3] <> [1,4]t
<kleiner als[1,2,3] < [1,4]t
>größer als[1,4,3] > [1,2,4]t
<=kleiner als oder gleich[1,2,3] <= [1,2,3]t
>=größer als oder gleich[1,4,3] >= [1,4,3]t
@>enthält[1,4,3] @> [3,1,3]t
<@ist enthalten in[2,7] <@ [2,5,7]t
&&überlappend[1,4,3] && [2,1]t
||Konkatenation[1,2] || [[4,6]]{{1,2},{4,6}}
||einfügen in3 || [4,5,6]{3,4,5,6}
||einfügen von[4,5,6] || 7{4,5,6,7}

Aus Platzgründen ist in den Beispielen das Schlüsselwort array weggelassen.

In der offiziellen Dokumentation sind noch zahlreiche vordefinierte Funktionen aufgelistet:

www.postgresql.org/docs/13/functions-array.html

Verarbeitung von Arrays

Aufzählungen / Enums

Aufzählungstypen geben einen geordneten Satz von zulässigen Zeichenketten vor:

Die Groß- und Kleinschreibung ist relevant, sodass in diesem Beispiel 'de' nicht als gültiger Wert gilt. Zudem sind Enums typsicher. Folglich lassen sich Werte von unterschiedlichen Aufzählungen nicht miteinander vergleichen.

Trotz der Repräsentation als Zeichenkette beansprucht ein Spaltenwert stets nur 4 Byte.

Verbünde / Composite Types

Ein zusammengesetzter Typ bildet die Struktur einer Zeile bzw. eines Datensatzes ab:

Beschränkungen wie not null bleiben nur Tabellenspalten vorbehalten. Jedoch kann mit domain ein Untertyp definiert werden, welcher derartige Prüfungen vornimmt.

Beim Zugriff auf einzelne Felder eines zusammengesetzten Wertes muss der Spaltenname in Rundklammern stehen, andernfalls geht PostgeSQL von einer Tabelle aus:

In gleicher Weise müssen Ausdrücke, welche einen zusammengesetzten Wert zum Ergebnis haben, von Rundklammern umschlossen sein:

select (f(PARAM)).field;

Darstellung zusammengesetzte Werte

Werte von zusammengesetzten Typen werden als Tupel dargestellt, entweder in Gestalt einer wohlformatierten Zeichenkette oder repräsentiert als eigenständiges literales Objekt:

Das Schlüsselwort row gestattet es, zusammengesetzte Werte (en composite values) außerhalb einer Zeichenkette als Tupel zu schreiben. Solange mehr als ein Feld vorliegt, kann auf das Schlüsselwort row sogar verzichtet werden.

Untertypen / Domain Types

Eine Domain in PostgreSQL ist ein benutzerdefinierter Datentyp, welcher auf einem anderen bestehenden Typen beruht:

Sofern keine Einschränkungen definiert werden, verhält sich eine Domain wie die zugrunde liegende Datenart

Domains sind ein ausgezeichnetes Mittel, um die Datenkonsistenz auf systematische und tabellenübergreifende Weise zu gewährleisten.

Pseudotypen

Pseudotypen (en pseudo-types) abstrahieren über konkrete Datenarten von Parametern und Funktionsergebnissen hinweg und ermöglichen damit im beschränkten Umfang – aber auf typischere Weise – generische Programmierung.

NameDatentyp verweist auf
any… ein beliebiges Eingabeobjekt
anyelement… ein beliebiges Objekt
anyarray… ein beliebiges Datenfeld
anynonarray… ein beliebiges Nichtdatenfeld
anyenum… ein beliebiges Aufzählungsobjekt
anyrange… einen beliebigen Bereich (en <range type)
anycompatible… ein automatisch umwandelbares Objekt
anycompatiblearray… ein automatisch umwandelbares Datenfeld
anycompatiblenonarray… ein automatisch umwandelbares Nichtdatenfeld
anycompatiblerange… einen automatisch umwandelbaren Bereich
record… eine einzelne unspezifische Tabellenzeile
trigger… eine Funktion mit einem Trigger als Rückgabe
event_trigger… eine Funktion mit einem Event-Trigger als Rückgabe
void… eine Funktion ohne Rückgabe
unknown… eine noch unbekannte Objektart (keine Typauflösung)

WITH-Klausel

Bei komplexen Operationen bietet es sich an, Unterfragen getrennt zu behandeln:

Solche Hilfsanweisungen mit with, auch als Common Table Expressions – CTE bezeichnet, stellen nichts anderes als temporäre Tabellen dar, welche nur für die darauffolgeden Datenbankoperation existieren (→ lokale Namensbindung).

Rollen und Rechteverwaltung

PostgresSQL verwaltet den Zugriff anhand von Rollen (en roles). Eine Rolle ist entweder ein einzelner Nutzer (en user) oder eine ganze Nutzerschaft. Demnach vereinigt PostgresSQL Nutzer und Gruppen, wie diese andere DB-Systeme voneinander unterscheiden, zu einem einzigen Konzept: Eine Rolle besitzt die Fähigkeiten sich einzuloggen, andere Rollen zu beerben, sowie Zugang zu ganz bestimmten Datenbankobjekten zu erhalten.

Privilegien

auch role attributes

create role <name> <attribute> …;

AttributNutzer
login… darf sich über seinen Namen einloggen
superuser… wird zum Superusers
createdb… darf Datenbanken erstellen
createrole… darf Rollen erstellen
replication… darf Daten zu einem anderen Server kopieren
password '<string>'… erhält ein eigenes Passwort
Häufige Befehle
Mitgliedschaften

Zum leichteren Verwalten von Zugriffsberechtigungen können mehrere Rolle von ein und derselben Rolle erben, sodass diese nichts anderes als eine Nutzergruppe mit gemeinsamen Rechten darstellt. Die Befehle grant und revoke erteilen oder entfernen Mitgliedschaften:

grant <user group> to <user> [, …]

revoke <user group> from <user> [, …]

Eigentümerschaften

Jedes Datenbankobjekt weist immer einen Eigentümer (en owner) vor; in der Regel jene Rolle, welche das Objekt erstellt hat:

Mit set role <name>; wird die gegenwärtig aktive Rolle gewechselt, sodass alle nachfolgend erstellten Datenbankobjekte dieser Rolle angehören. Die Eigentümerschaft kann auch nachträglich geändert werden:

alter table <name> owner to <role>;

Zugriffsberechtigungen

Auf ein Datenbankobjekt darf nur über eine Rolle zugegriffen werden, die zur Eigentümerschaft gehört. Jedoch lassen sich spezifische Zugriffsberechtigungen für Nichteigentümer definieren:

ArtRolle erhält das Recht
select… abzufragen
insert / update / delete / truncate… Daten zu manipulieren
references… Fremdschlüsselbeziehung zu erstellen

Zugriffsberechtigungen werden mit grant erteilt

grant [select, insert, … | all] on <table> to <role> [, <other role>, …];

und mit revoke aufgehoben,

revoke [select, insert, … | all] on <table> from <role> [, …];

ausgehend von der Rolle eines Eigentümers, wozu auch Superuser gehört.

Es ist auch möglich, über die spezielle Rolle public Berechtigungen an alle im System bestehenden Rollen zu erteilen:

grant … on … to public;

Zeilenschutz

Ergänzend zum Zugriffsberechtigungssystem von SQL führt PostgresSQL unter dem Begriff row security policies auch Sicherheitsrichtlinien auf Zeilenebene ein, um Tabellenoperationen zeilenweise zu beschränken.

Als Erstes muss der Zeilenschutz aktiviert werden:

alter table <table> enable row level security

Die Deaktivierung erfolgt mittels disable.

Durch das Aktivieren des Zeilenschutzes findet die Verweigerungsrichtlinie Anwendung, sodass auch Rollen, die eigentlich zugriffsberechtigt sind, keine Zeilen für Abfragen oder Manipulationen angezeigt bekommen. Jedoch erfasst die Verweigerungsrichtlinie nur zeilenweise Operationen; berechtigte Rollen können dennoch mittels truncate die Tabelle als Ganzes entleeren.

Ausgenommen vom Zeilenschutz sind der Eigentümer sowie die Rolle Superuser. Jedoch kann der Eigentümer mit force ebenfalls in das Sicherheitssystem einbezogen werden:

alter table <table> force row level security

Die entsprechende Deaktivierung erfolgt mittels no force.

Sicherheitsrichtlinien

Sicherheitsrichtlinien auf Zeilenebene werden mit create policy erstellt, mit alter policy verändert und mit drop policy gelöscht, vorausgesetzt der Zeilenschutz ist aktiviert, andernfalls sind die Befehle wirkungslos:

Die Police (en policy) ist vergleichbar mit einem benannten Check-Constraint: Die angegebene Bedingung muss true zurückliefern, andernfalls besteht kein Zugriff auf den betreffenden Datensatz. Im weiteren Sinne filtert eine Police alle ein- und ausgehenden Daten wie eine Where-Klausel. 

Schemen

Die folgenden Datenbankobjekte bilden jeweils voneinander unabhängige Namensräume: 

Es ist ersichtlich, dass Namenskollisionen, bspw. zwischen Tabellen und benutzerdefinierten Datentypen, kaum vermeidbar sind. Abhilfe können Schemen schaffen, welche über einen eigenen Namensraum verfügen:

create schema <name>;

alter schema <name> owner to <role>;

drop schema <name> [cascade];

Der Zugriff auf Datenbankobjekte eines anderen Schemas erfolgt in gewohnter Punktnotation:

select * from <schema>.<table>;

Ist kein Schema spezifiziert, sucht PostgreSQL in jenen Schemen nach dem genannten Datenbankobjekt, welche in der Variable search_path aufgelistet sind, beginnend von links:

show search_path;

set search_path to <schema> [, <another schema>];

alter database <db> set search_path to …;

alter role <role> set search_path to …;

Rechte an Schemen

Als vollwertige Datenbankobjekte lassen sich Schemen für bestimmte Nutzer freigeben oder sperren:

grant usage on schema <name> to <role>;

grant all privileges on all tables in schema <nem> to <role>;

Systeminformationen

FunktionRückgabeBeschreibung
current_catalognamename of current database (called "catalog" in the SQL standard)
current_database()namename of current database
current_query()texttext of the currently executing query, as submitted by the client (might contain more than one statement)
current_rolenameequivalent to current_user
current_schema[()]namename of current schema
current_schemas(boolean)name[]names of schemas in search path, optionally including implicit schemas
current_usernameuser name of current execution context
inet_client_addr()inetaddress of the remote connection
inet_client_port()intport of the remote connection
inet_server_addr()inetaddress of the local connection
inet_server_port()intport of the local connection
pg_backend_pid()intProcess ID of the server process attached to the current session
pg_column_size()regtypeSize in bytes of the passed value
pg_listening_channels()setof textchannel names that the session is currently listening on
pg_my_temp_schema()oidOID of session's temporary schema, or 0 if none
pg_trigger_depth()intcurrent nesting level of PostgreSQL triggers (0 if not called, directly or indirectly, from inside a trigger)
pg_typeof()regtypeData type of the passed value
session_usernamesession user name
usernameequivalent to current_user
version()textPostgreSQL version information
Anzahl an Einträgen in allen Tabellen

Prozedurale Erweiterungen

PL/pgSQL

PL/pgSQL – ausgeschrieben Procedural Language/PostgreSQL Structured Query Language – ist die prozedurale Sprache der objektrelationalen Datenbank PostgreSQL.

Variablen und Blöcke

PL/pgSQ ist eine strukturierte Sprache, wo jede Anweisung von einem Block umschlossen sein muss. Als Konsequenz sind Variablen – im Gegensatz zu anderen prozeduralen Erweiterungen – nicht wahllos deklarierbar, sondern dürfen nur im Kopf eines Anweisungsblocks bekannt gemacht werden:

Das Schlüsselwort do kündigt einen anonymen Block an, welcher anders als Funktionsblöcke nicht über einen eigenen aufrufenden Namen verfügt (→ callable unit), sondern stattdessen an Ort und Stelle ausgeführt wird.

Blöcke sind beliebig ineiander verschachtelbar, einschließlich derer von Funktionen (→ closure).

Kontrollstrukturen

Verzweigungen

Die folgenden Funktionen können als Kontrollstrukturen aufgefasst werden, da deren Argumente nur nach Bedarf ausgewertet werden (→ lazy evaluation):

Schleifen und Abbruchbedingungen

PostgreSQL unterstützt sogar Mengenschleifen:

Ausnahmebehandlungen

Funktionen

Funktionsblöcke werden in Form von Stringliteralen definiert:

Um nicht weitere Hochkommas von Zeichenketten oder auch Namen innerhalb des Funktionsrumpfs maskieren zu müssen, besteht die Schreibweise mit doppeltem Dollarzeichen als alternatives Trennzeichen (→ dollar-quoted literal),

was nicht zuletzt auch eine Syntaxhervorhebung in Texteditoren ermöglicht.

Anmerkung

In PostgreSQL sind Zeichenkettenliterale allgemein mit doppelten Dollarzeichen erlaubt:

select $$ Hallo Welt! $$

Jedoch sollte davon kein Gebrauch gemacht werden.

Sprachauswahl

Die Sprachangabe lässt vermuten, dass nicht nur plpgsql zur Auswahl steht:

Die Schreibweise als Zeichenkettenliteral ist darauf zurückzuführen, dass Funktionsrümpfe in verschiedenen Sprachen definiert werden können. So ist beispielsweise Python über eine Erweiterung nachrüstbar. PL/pgSQL stellt lediglich die native und – abgesehen von direktem C – effektivste Lösung dar, wobei sich Funktionen auch in reinem SQL ohne prozedurale Erweiterung schreiben lassen:

Als Fausregel gilt, reines SQL gegenüber PL/pgSQL zu bevorzugen, solange keine Variablen oder komplexe Kontrollstrukturen benötigt werden.

Parameter

Parameter müssen nicht zwangsweise einen Namen vorweisen:

PostgreSQL erlaubt das Überladen von Funktionen, solange sich deren Parameter in Anzahl oder Typ voneinander unterscheiden.

Zusammen mit Arrays sind sogar variadische Funktion definierbar:

Rückgabe anonymer Verbünde

Eine weitere Möglichkeit, den Rückgabetypen einer Funktion zu fixieren, besteht in der Festlegung von Ausgabeparametern:

Der Vorteil gegenüber einer RETURNS-Klausel liegt darin, dass mehr als ein Wert gleichzeitig zurückgeliefert werden kann, ohne erst einen Verbundtypen mit create type … definieren zu müssen.

Bei fehlender Angabe eines Modifikators wird in implizit angenommen.

Volatilitätskategorien

Jede Funktion weist eine Volatilitätsklassifizierung (en function volatility categories) auf, womit nichts anderes als ein Versprechen an den Optimierer gemeint ist:

ModifikatorVersprechen 
volatilekeine (voreingestellt) 
stableFunktion verändert keine bestehenden Datensätze 
immutableFunktionsergebnis hängt ausschließlich von den Parametern ab 

Die Verantwortung über die Korrektheit einer solcher Angabe obliegt dem Programmierer. Als Faustregel gilt, immutable gegenüber stable, und stable gegenüber volatile zu bevorzugen. Jedoch sollten Funktionen nur dann als stable gekennzeichnet werden, wenn Daten lediglich mittels SELECT abgefragt werden, ohne diese zu manipulieren oder gar zu löschen. Der Modifikator immutable ist allenfalls bei reinen Funktionen (→ referentielle Transparenz) zu empfehlen.

Überladen von Operatoren

Bestehende Operatoren lassen sich überladen:

Die wahlfreie Angabe eines Kommutators oder Negators dient lediglich zu etwaigen Optimierungen.

PostgreSQL erlaubt unter gewissen Einschränkungen auch das Erstellen von neuen Operator mit benutzereigenen Symbolen.

Nullproblematik

Null ist Fluch und Segen zugleich: Einerseits erscheint die Handhabung in SQL, das Fehlen eines Wertes universell als NULL auszudrücken, sehr einfach und effizient; andererseits bleibt – aufgrund der fehlenden Widerspieglung im Typsystem – ausnahmslos die ganze Arbeit beim Programmierer hängen, stets dafür zu sorgen, dass Operationen trotz Nullwerte wie gewünscht ablaufen. Funktionen als strict zu kennzeichnen, kann eine mögliche Abhilfe schaffen:

Eine stricte Funktion gibt automatisch NULL zurück, sobald auch nur ein einziges Argument zu NULL evaluiert. Somit kann der Programmierer den Rückgabewert auf NULL prüfen und etwaige Sonderbehandlungen vorgeben, ohne auf Exceptions zurückgreifen zu müssen. Jedoch ist zu beachten, dass als strict gekennzeichnete Funktionen meist wegen unmöglicher Inline-Ersetzung nicht optimiert werden. Daher ist zu empfehlen, selbst etwaige Prüfungen zu programmieren:

Gespeicherte Prozeduren

 

 

Nachrichten und Fehler

raise <level> <format>;

mit <level> gleich debug | log | notice | info | warning | exception

Beispiel

Das Prozentzeichen fungiert als Platzhalter für die nachfolgend aufgelisteten Ausdrücke.

Trigger

 

 

PL/SQL

MySQL bzw. MariaDB implementieren zumindest eine Teilmenge von PL/SQL.

Anweisungsblöcke

Mehrere Anweisungen lassen sich zu einem Block zusammenfassen: 

Anweisungen erfordern stets ein Semikolon ; als Befehlsabschluss.

Variablen

Vom Benutzer angelegte Variablen gelten nur für eine Sitzung (en session), können aber zwischen mehreren Abfragen und abgelegten Unterprogrammen geteilt werden.

Beim Aufruf einer Variable muss das Adresszeichen @ vorangestellt werden. Fehlt das Adresszeichen, liegt hingegen nur eine lokal sichtbare Variable vor, beschränkt auf den Scope des umgebenden Blocks.

Systemvariablen sind vordefinierte Werte zum Konfigurieren von Datenbankoperationen  und unterscheiden sich durch zwei vorangestellte Adresszeichen @@ von den übrigen Variablen.

Kontrollstrukturen

MariaDB unterstützt die wesentlichen Konstrukte zum Steuern des Programmablaufs:

Funktionen

Benutzerdefinierte Funktionen

Prozeduren

Gleichermaßen als Datenbankobjekte abgespeichert fassen benutzereigene Prozeduren ein oder mehr Anweisungen zusammen:

Im Gegensatz zu Funktionen geben Prozeduren keinen Wert zurück, sondern verändern über Referenzen bestehende Daten. Wie weitreichend über einen Parameter eingegriffen werden darf, ist durch einen von drei möglichen Zugriffsmodifikatoren festzulegen:

Attribut Zugriffsrecht Auswirkung
in nur lesend → Bei Veränderung wird eine lokale Kopie angelegt.
out nur schreibend → Der Parameter ist uninitialisiert (NULL).
inout lesend / schreibend → Statt einer Kopie wird die äußere Variable überschrieben.

Bei einem als out gekennzeichneten Parameter verläuft der Datenfluss nur aus der Prozedur heraus. Der Anfangswert der übergebenen Variable ist nicht lesbar. Stattdessen bleibt der Parameter auf NULL gesetzt, solange nicht innerhalb der Prozedur eine Wertzuweisung erfolgt. 

Persönliche Konventionen

SQL im Allgemeinen und Implementierungen wie PostgreSQL weisen extrem viele Schlüsselwörter auf. Der Rückgriff auf angefügte Unterstriche kann hier für gewisse Erleichterung sorgen und gleichzeitig Namenskollisionen von vornherein ausschließen:

DatenbankobjektKennzeichenBeispiele
Schemalediglich kleingeschriebenlogistics
Tabelle, Datentyplediglich kleingeschriebenbooking_year
Einwegtabelleumschlossen von __person_
ConstraintText in Anführungszeichen"either x or y"
Triggersystematischbefore_insert_job
Prozedur, Funktionlediglich kleingeschriebenbuild_tables
bloße Implementierungenumschlossen von ____check_cw__
boolean als Rückgabetypgepräfixt mit is_is_valid_cw
— spezifische Spaltenabfragesystematischlocation_name
Parameter, Variablegepräfixt mit __txt

Auf CamelCase sollte verzichten werden, da SQL standardgemäß nicht zwischen Groß- und Kleinbuchstaben unterscheidet. Stattdessen sollten die Bestandteile von zusammengesetzten Begriffen mittels Unterstriche voneinander getrennt werden. Der Rückgriff auf Hochkammas bei Namen – vor allem von Tabellen, Spalten oder auch Funktionen – ist absolut nicht zu empfehlen. Jedoch kann diese Möglichkeit bezüglich Constraints, dessen Bezeichner nur bei Fehlermeldungen angezeigt werden, durchaus sinnvoll sein, um kurze Erläuterungen statt wenig sagende Namen wie tabelle_ck_spalte auszugeben.

Aus Gründen der Einfachheit ist zu empfehlen, sogar Schlüsselwörter durchgängig kleinzuschreiben, da moderne Texteditoren problemlos die Syntax hervorheben können! Heutzutage besteht absolut kein Grund mehr, noch die Tastaturakrobatik zu vollführen, zwanghaft KEYWORDS zu UPPERCASEN. Eine Ausnahme stellen lediglich Abfragen in Form von Zeichenketten über eine Hostsprache dar, um mittels durchgehender Großschreibung die fehlende Syntaxhervorhebung zu kompensieren.

Handhabung

PostgreSQL

In PostgreSQL wird ein Benutzerkonto als Rolle bezeichnet. Standardmäßig verwendet PostgreSQL die Ident-Authentifizierung, sodass Rollen den Systemkonten von Linux zugeordnet sind.

Bei der Installation wird automatisch ein Benutzerkonto namens postgres erstellt, welches der Standardrolle postgres angehört (→ database superuser). Um eine Verbindung herzustellen, ist zum Postgres-Konto zu wechseln:

> sudo -i -u postgres

> psql

Oder ohne Umweg:

> sudo -u postgres psql

In der interaktiven Umgebung von PostgreSQL (en interactive command prompt) sollte als erstes ein neues Passwort festgelegt werden:

postgres=# alter user postgres password 'Pa$$w0rd';

Prompt
AufgabeBefehlLangform
Prompt beenden\q`\quit
Übersicht aller Befehle\? (Beendigung mit q) 
Liste aller Datenbanken\l\list
Verbindung aufbauen\c <db name> [<role name>]\connect
Passwort ändern \password
Liste aller Relationen\d 
Liste aller Tabellen\dt 
Tabellenbeschreibung\d <table name> 
Liste aller Schemen\dn 
Liste aller Funktionen\df 
Liste aller Sichten\dv 
Liste aller Rollen\du 
Übersicht aller erteilter Rechte\dp 
aktuelle Version von pgSQLSELECT version(); 
letzten Befehl wiederholen\g 
Anzeige der Befehlshistorie\s 
Sichern der Befehlshistorie\s <file name> 
Wechsel zur HTML-Ausgabe\H 
Hinzufügen von Nutzern und Rechten
Frontends zum Verwalten von Postgres-Datenbanken

Interaktion mit Python

Empfohlen wird der Datenbanktreiber psycopg in Version 2 – Stand 2021:

pip install psycopg2

Unter Linux sind noch zuvor folgende Abhängigkeiten zu installieren:

sudo apt install python3-dev libpq-dev

Quelle: www.psycopg.org/install/

MariaDB

> sudo mysql -u root -p # einloggen als root

Neues Passwort einrichten

Anschließend beenden exit und Neustarten mit sudo service mysql restart.

Zu Entwurfszwecken ist ein einfaches Passwort wie Pa$$w0rd zu empfehlen.

Spezifische Befehle

Zum Verwalten des Servers bietet MariaDB eine Reihe von Anweisungen (→ Semikolon als Abschlusszeichen), welche in die Syntax von SQL eingebettet sind:

AufgabeAnweisung
Anzeigen aller Datenbanken / Schemenshow {database| schemas}
— mit Filterung… [like <pattern> | where <expr>]

SQLite

Nach Installation ist die interaktive Umgebung direkt zugänglich:

SQLite-eigene Befehle werden mit einem vorangestellten Unterpunkt aufgerufen (→ SQLite dot commands) und ohne Semikolon als Abschlusszeichen.

Im Gegensatz zu MariaDB oder anderen Datenbanken sind ebenso keine besonderen Rechte erforderlich, um eine neue Datenbank zu erzeugen:

> sqlite3 DatabaseName

Falls die angegebene Datenbank noch nicht existiert, wird diese automatisch angelegt.

AufgabeBefehl
Anzeige aller verbundener Datenbanken.databases
Auflisten aller Tabellen.tables
Einlesen und Ausführen einer SQL-Datei.read x.sql
Datenbankverbindungen

Bei Verbindung zu einer Datenbankdatei lädt SQLite diese unter dem Namen main, unabhängig vom tatsächlichen Dateinamen. Ein anderer Bezeichner ist nicht wählbar. Über temp kann auf die zwischengespeicherten Tabellen und anderen Datenbankobjekte einer Verbindung zugegriffen werden.

Neben der primären Datenbank main erlaubt SQLite das Einbinden von weiteren Nebendatenbanken:

attach database 'FILENAME' as 'ALIAS';

detach database 'ALIAS';

Daten aus CSV-Dateien

Zuerst muss eingestellt werden, dass die einzulesende Datei als CSV zu interpretieren ist:

sqlite> .mode csv

Erst dann lassen sich die Datensätze in eine Tabelle importieren:

sqlite> .import <path> <table>

Und zur abschließenden Kontrolle der neuen Datensätze:  

sqlite> .schema <table>

Anhang

PostgreSQL vs MariaDB vs SQLite

Welches Datenbanksystem ist das richtige? Die Antwort hängt vom jeweiligen Anwendungsfall ab: