PL/pgSQL
# PL/pgSQL

PL/pgSQL (Procedural Language/PostgreSQL Structured Query Language) ist eine prozedurale Sprache der objektrelationalen Datenbank PostgreSQL. Die Syntax von PL/pgSQL ist wie bei PL/SQL auf Oracle-Datenbanksystemen stark an Ada angelehnt.

PL/pgSQL wurde zur Erweiterung des SQL-Funktionsumfangs eingeführt, dabei kann PL/pgSQL-Code als Stored Procedure in der Datenbank selbst gespeichert sein. Unterstützt werden Variablen, Bedingungen, Schleifen, Funktionen, Datenbankcursor und Ausnahmebehandlungen. PL/pgSQL-Code kann sowohl aus SQL-Kommandos als auch aus Datenbanktriggern heraus aufgerufen werden.

Mit Hilfe der prozeduralen Erweiterung lassen sich SQL-Befehle direkt im PostgreSQL-Server dynamisch erzeugen und müssen nicht mehr als Text über eine Datenbankschnittstelle übergeben werden, wie dies z. B. bei ODBC, JDBC und OLE DB der Fall ist, sondern können direkt in der Datenbank erstellt und ausgeführt werden.

## Verwendung

* PL/pgSQL-Code kann von einem Datenbank-Frontend an PostgreSQL übergeben und dort direkt abgearbeitet werden.
* PL/pgSQL-Code kann (als Stored Procedure) dauerhaft in der Datenbank gespeichert werden um den Funktionsumfang der Datenbank zu erweitern.
* Über Berechtigungen (sogenannte „Rollen“) kann jeder Benutzer oder jede Benutzergruppe der Datenbank die Funktionen nutzen, die für deren Rolle vorgesehen sind. Auf diese Weise lässt sich die Sicherheit vor unbefugten Zugriffen deutlich verbessern.
* Verwendung in Datenbanktriggern
* Die Performance lässt sich oft enorm steigern, wenn PL/pgSQL-Programme direkt in der Datenbank ausgeführt werden, insbesondere wenn sich dadurch die Kommunikation zwischen Prozessen oder der Netzwerkverkehr, falls Datenbank und Anwendungsserver auf unterschiedlicher Hardware ausgeführt werden, vermeiden lässt.

## Grundlegender Aufbau

PL/pgSQL-Programme bestehen aus Blöcken:

## Beispiel

Das Beispiel schreibt eine "Hallo Welt"-Notiz.

## Variablendefinitionen

Variablen werden im optionalen Abschnitt DECLARE definiert und optional initialisiert.

:= ist der Zuweisungsoperator, mit dem man einer Variable einen Wert zuweist. Im DECLARE Abschnitt kann für Zuweisungen alternativ auch DEFAULT verwendet werden.

### Zahlenvariablen

Um eine Zahlenvariable zu definieren, schreibt man den Variablennamen gefolgt vom Variablentyp NUMERIC.

Hinter diesem schreibt man in runden Klammern die Genauigkeit precision sowie optional ein Komma und die Anzahl an Nachkommastellen scale. Gibt man NUMERIC ohne Klammern an gelten für die Genauigkeit bis zu 131072 Stellen vor dem Dezimalpunkt und bis zu 16383 Stellen nach dem Dezimalpunkt.

Genauigkeit entspricht in diesem Fall der Anzahl an Stellen, welche die Variable enthalten kann, und nicht dem Wertebereich.

Auswahl weiterer Datentypen für Zahlenvariablen:

### Textvariablen

Um eine Textvariable zu definieren, schreibt man den Variablennamen gefolgt vom Variablentyp VARCHAR. Hinter diesem schreibt man die Anzahl der Zeichen, die in der Variable gespeichert werden können, in Klammern. Soll die Textvariable nach sprach- oder benutzerdefinierten Kriterien sortiert werden, kann man das Schlüsselwort COLLATE gefolgt vom Collationsname z. B. "en_US" verwenden. Weiterer Datentypen für Textvariablen sind:

### Boolean

Kann TRUE, FALSE oder NULL sein.

### Datum und Uhrzeit

Um eine Datumsvariable zu definieren schreibt man den Variablennamen gefolgt vom Variablentyp DATE. Zum Konvertieren von Datum und Uhrzeit stellt PostgreSQL eine Reihe von Funktionen zur Verfügung. Hier wurde TO_DATE verwendet. Diese Funktion wandelt den Text zwischen den ersten Hochkommas in ein Datum mit dem angegebenen Format zwischen den zweiten Hochkommas um. Weitere Datum- und Zeit-Datentypen sind:

Mit dem optionalen Statement (p) kann die Anzahl der Stellen der Sekundenbruchteile präzisiert werden.

### Datentyp über Tabelle oder Spalte festlegen

%TYPE definiert eine Variable des Typs der angegebenen Spalte. %ROWTYPE definiert eine Variable des Typs der angegebenen Tabelle. Weil jede Tabelle in PostgreSQL implizit einen gleichnamigen Zeilentyp generiert, darf %ROWTYPE auch weggelassen werden.

Beispiel:

## Steuerung des Programmablaufs

### Rückgabe der Funktion

Mit dem Schlüsselwort RETURN wird die Rückgabe an die Funktion definiert. Soll die Funktion Datensätze mit Hilfe des Schlüsselwortes SETOF zurückgeben, kann das mit RETURN NEXT oder RETURN QUERY realisiert werden. Mit Hilfe von USING können Parameter in den SQL-Befehl eingefügt werden.

In folgendem Beispiel wird RETURN NEXT verwendet:

### Verzweigung des Programmablaufs

Mit Hilfe von Bedingungen kann der Programmablauf gesteuert werden. Je nach Situation werden die Befehle im dafür vorgesehenen Abschnitt abgearbeitet.

**IF THEN**

IF prüft, ob eine Bedingung erfüllt ist. Trifft die Bedingung zu, wird der Code nach dem THEN und ausgeführt und ansonsten übersprungen. Mit ELSIF können weitere Bedingungen hinzugefügt werden. Ist eine ELSE vorhanden wird der darauf folgende Code ausgeführt, falls keine der Bedingungen zutrifft. Trifft mehr als eine der Bedingungen zu, wird nur die erste wahre Bedingung ausgeführt, und alle anderen wahren Bedingungen übersprungen. Die Schlüsselwörter ELSEIF und ELSIF sind Synonyme.

**CASE WHEN**

Die CASE-Anweisung bietet zwei unterschiedliche Wege, im ersten Fall wird nach dem CASE ein Suchausdruck angegeben. Dieser Ausdruck wird im Ausdruck der WHEN folgt gesucht und anschließend wird der Code nach dem THEN ausgeführt. Nach dem WHEN können auch mehrere durch Kommas getrennte Ausdrücke ausgewertet werden. Im zweiten Fall folgt dem CASE das WHEN direkt, und danach wird eine Bedingung angegeben. Trifft diese zu wird der Code nach dem THEN ausgeführt. In beiden Fällen wird der dem ELSE folgende Code ausgeführt, wenn nichts gefunden wurde. mit END CASE wird die CASE-Anweisung abgeschlossen. Wie zuvor bei IF THEN wird nur der der ersten gültigen Bedingung folgende Codeabschnitt ausgeführt.

Beispiel für Verzweigung des Programmablaufes mit IF THEN und CASE WHEN:

### Schleifen

Mit den Schlüsselwörtern LOOP, EXIT, CONTINUE, WHILE, FOR und FOREACH können Anweisungsblöcke wiederholt durchlaufen werden.

**Einfache LOOP Schleife**

Die einfache LOOP Schleife endet sobald ein EXIT die Schleife oder ein RETURN die Funktion beendet. Folgt hinter dem EXIT ein WHEN mit einer Bedingung, wird die Schleife nur bei erfüllter Bedingung verlassen. PL/pgSQL erlaubt es Schleifen zu benennen. Der LOOP Block wird auf jeden Fall bis zum EXIT durchlaufen, egal ob die Bedingung auch schon zuvor zutraf. Mit der CONTINUE WHEN Anweisung kann ein Teil der Schleife bedingt ausgeführt werden.

Der Name eines Blocks wird zwischen doppelten größerkleiner Zeichen <<>>festgelegt wie <<label>> oberhalb. Die Benennung verbessert die Lesbarkeit des Codes.

In diesem Beispiel wird der benannte Block "ablock" solange durchlaufen bis j=42 ist. Sobald das j größer als 21 wird, werden Notizen ausgegeben:

**WHILE LOOP Schleife**

Die einfache WHILE LOOP Schleife wird nur durchlaufen wenn die Eingangsbedingung erfüllt ist, und endet sobald die Bedingung nicht mehr zutrifft. Auch diese Variante kann benannt werden.

**FOR Schleifen**

Die FOR-Schleife zählt eine Indexvariable vom Type INTEGER die auch automatisch erstellt wird von einem festgelegten Startwert bis zu einem festgelegten Endwert. Start- und Zielwert sind durch zwei Punkte getrennt. Gibt man das Schlüsselwort REVERSE nach dem IN an, so wird vom größeren zum kleineren Wert heruntergezählt. Die Schrittweite ist aber in jedem Falle positiv anzugeben, auch beim Rückwärtszählen.

Die FOR-Schleife kann auch zum Durchlaufen einer Abfrage verwendet werden:

Die “wertliste” ist dabei eine Variable die die Felder der Abfrage “query” übernimmt. Die Variable wertliste übernimmt beim Durchlaufen der Abfrage jede Zeile der Abfrage einmal. Mit dieser Zeile wird dann der Schleifenkörper durchlaufen.

Verwendet man statt einer erst “vor Ort” bei der FOR-Schleife definierten Abfrage (bzw. einem SQL-String via EXECUTE) einen expliziten Cursor, so wird in ausreichend neuen PostgreSQL-Versionen (9.x) die Schleifenvariable “wertliste” (analog zum Schleifenindex einer numerischen FOR-Schleife) implizit deklariert.

