PL/SQL
PL/SQL | |
---|---|
Paradigmen: | prozedural |
Erscheinungsjahr: | 1991 |
Entwickler: | Oracle |
Aktuelle Version: | 11.1 (2009) |
Typisierung: | stark, statisch, explizit |
Wichtige Implementierungen: | Oracle-Datenbank |
Beeinflusst von: | Ada, SQL |
Lizenz: | proprietär |
Oracle Technology Network |
PL/SQL (Procedural Language/Structured Query Language) ist eine proprietäre Programmiersprache der Firma Oracle.
PL/SQL verbindet die Abfragesprache SQL mit einer prozeduralen Programmiersprache. Die Syntax ist stark an die Programmiersprache Ada angelehnt.
Unterstützt werden Variablen, Bedingungen, Schleifen und Ausnahmebehandlungen. Ab Version 8 des Oracle-RDBMS halten auch objektorientierte Merkmale Einzug.
PL/SQL ist für das Arbeiten mit Oracle-Datenbanken ausgelegt. Insbesondere kann man im Quelltext SQL-Befehle nach dem Oracle-Standard einfügen. Dabei werden die SQL-Anweisungen nicht als Zeichenketten erzeugt und an eine Datenbankschnittstelle übergeben (wie z. B. bei ODBC, JDBC u. ä.), sondern fügen sich nahtlos in den Programmcode ein. Die Syntax kann damit bereits zum Zeitpunkt der Kompilierung überprüft werden.
Die prozedurale Erweiterung der SQL-Abfragesprache wird inzwischen auch von vielen anderen Datenbankherstellern implementiert. Daher wurde diese prozedurale SQL-Erweiterung inzwischen vom ANSI-Gremium standardisiert.
Verwendung
[Bearbeiten | Quelltext bearbeiten ]- Man kann PL/SQL-Code wie SQL-Befehle über ein Datenbank-Frontend absetzen, der dann direkt abgearbeitet wird.
- Man kann einzelne Unterprogramme (Stored Procedures) oder Bibliotheken mehrerer Unterprogramme (Stored Packages) als dauerhafte Datenbankobjekte auf dem Datenbankserver speichern und damit die Funktionalität der Datenbank erweitern; jeder Benutzer der Datenbank kann diese Unterprogramme aufrufen und nutzen. Die Berechtigungen können für jedes einzelne PL/SQL-Paket an einzelne Benutzer oder Benutzergruppen (sogenannte „Rollen") vergeben werden.
- Programmierung von Datenbanktriggern
- Programmierung in diversen Tools (Oracle-Forms, Oracle-Reports)
PL/SQL-Programme können die Performance verbessern, wenn der Aufruf von einem Applikationsserver ausgeführt wird, der über eine langsame Netzwerkverbindung mit dem Datenbankserver verbunden ist. So muss in diesem Fall nur zu Beginn und am Ende der Ausführung eine Nachricht über das Netzwerk transportiert werden. Es gibt aber auch andere Möglichkeiten, bei einem langsamen Netzwerk die Performance einer Applikation zu verbessern. So kann z. B. die Oracle-Datenbank auch Java-Programme ausführen, die die Datenbank-Manipulationen vornehmen.
Grundlegender Aufbau
[Bearbeiten | Quelltext bearbeiten ]PL/SQL-Programme bestehen aus Blöcken:
declare -- Deklarationsblock begin -- Ausführungsteil exception -- Ausnahmeverarbeitung end; /* So kommentiert man mehrzeilig */ --So kommentiert man einzeilig
Variablendefinitionen
[Bearbeiten | Quelltext bearbeiten ]Variablen werden im (optionalen) Deklarationsabschnitt definiert und optional initialisiert.
declare zahl1number(2); zahl2number(2):=17; textvarchar(20):='Das ist ein Text'; begin selecthausnummerintozahl1fromAdressverzeichniswherename='Meier'andrownum=1; end;
:=
ist der Zuweisungsoperator, mit dem man einer Variable einen Wert zuweist.
Zahlenvariablen
[Bearbeiten | Quelltext bearbeiten ]variablennamenumber(P[,S]):=Wert;
Um eine Zahlenvariable zu definieren, schreibt man zum Beispiel den Variablennamen, gefolgt vom Variablentyp NUMBER
.
Hinter diesem schreibt man in runden Klammern die Genauigkeit P
sowie optional ein Komma und die Anzahl an Nachkommastellen S
.
Genauigkeit entspricht in diesem Fall der Anzahl an Stellen, welche die Variable enthalten kann, und nicht dem Wertebereich.
Auswahl weiterer Datentypen für Zahlenvariablen:
dec,decimal,double precision,integer,int,numeric,real,smallint,binary_integer,pls_integer
Textvariablen
[Bearbeiten | Quelltext bearbeiten ]variablennamevarchar2(L):='Text';
Um eine Textvariable zu definieren, schreibt man den Variablennamen gefolgt vom Variablentyp VARCHAR2
.
Der angehängte Längenconstraint (Integer in Klammern) gibt die maximale Länge der Variablen in Bytes an (sofern die Length Semantic nicht auf CHAR gestellt ist).
Auswahl weiterer Datentypen für Textvariablen:
CHAR,NCHAR,NVARCHAR2,CLOB,NCLOB
Die Datentypen LONG, LONG RAW und VARCHAR sind deprecated.
Boolean
[Bearbeiten | Quelltext bearbeiten ]variablennameboolean:=true;
Kann TRUE
, FALSE
oder NULL
sein.
Datum
[Bearbeiten | Quelltext bearbeiten ]datum_1date; datum_2date:=to_date('31.12.2016','DD.MM.YYYY'); datum_3date:=to_date('31.12.2016 23:59:59','DD.MM.YYYY HH24:MI:SS'); datum_4date:=date'2016年12月31日 ';
Variablen vom Typ DATE
enthalten Datum und Uhrzeit sekundengenau. Um eine Datumsvariable zu definieren schreibt man den Variablennamen gefolgt vom Variablentyp DATE
.
Die Funktion TO_DATE
wandelt den Text zwischen den ersten Hochkommas in ein Datum mit dem angegebenen Format zwischen den zweiten Hochkommas um, wobei die Angabe einer Uhrzeit optional und der Default 00:00:00 Uhr ist. Ein Datum ohne Uhrzeitanteil kann ohne Konvertierung von Zeichenkette zu Datum mit einem Datumsliteral definiert werden; man schreibt dann das Schlüsselwort date
, gefolgt von Datum im Format 'JJJJ-MM-TT'.
Um ein Datum in einen Text zu konvertieren, gibt es die Funktion TO_CHAR(Datum)
.
Neben dem Datentyp date
gibt es noch den Datentyp timestamp
, der eine größere Präzision hat. Hierzu gibt es weitere Subtypen: timestamp with time zone
speichert die Zeitzone mit den Zeitinformationen, timestamp with local timezone
konvertiert jeweils von der Zeitzone der Session in die lokale Zeitzone des Datenbankservers.
Datentyp über Spalte festlegen
[Bearbeiten | Quelltext bearbeiten ]VariablennameTabellenname.Spaltenname%type;
Definiert eine Variable des Typs der angegebenen Spalte.
Datentyp über Tabelle festlegen
[Bearbeiten | Quelltext bearbeiten ]VariablennameTabellenname%rowtype;
Definiert eine Variable für einen Datensatz/Row des Typs der angegebenen Tabelle.
Beispiel:
CURSORcursor_nameIS SELECT* FROMtabelle; variabletabelle%rowtype; ... FORiINcursor_nameLOOP variable:=i; andere_variable:=variable.SPALTENNAME; ENDLOOP;
Gültigkeitsbereich von Variablen
[Bearbeiten | Quelltext bearbeiten ]PL/SQL erlaubt es, Blöcke zu verschachteln. Variablen, die in äußeren Blöcken deklariert werden, sind in allen inneren Blöcken gültig. Variablen, die in inneren Blöcken deklariert werden, sind nicht in äußeren Blöcken gültig.
Je nachdem, wo Variablen deklariert werden, kann man zwischen zwei Arten unterscheiden.
- Lokale Variablen – Diese werden in einem inneren Block deklariert. Von außen kann nicht darauf zugegriffen werden.
- Globale Variablen – Diese werden in einem äußeren Block deklariert, und es kann von außen und innen darauf zugegriffen werden.
In folgendem Beispiel werden zwei Variablen deklariert, und die Summe derer wird in einem inneren Block einer dritten Variable zugewiesen. Auf die Variablen var_num1
und var_num2
kann von überall des Blocks aus zugegriffen werden. Auf die Variable var_result
dagegen, welche im inneren Block deklariert wurde, kann von außerhalb nicht zugegriffen werden.
DECLARE var_num1NUMBER; var_num2NUMBER; BEGIN var_num1:=100; var_num2:=200; DECLARE var_resultNUMBER; BEGIN var_result:=var_num1+var_num2; END; /* Auf var_result kann hier nicht zugegriffen werden */ END;
Konstanten
[Bearbeiten | Quelltext bearbeiten ]Eine Konstante ist ein Wert in einem PL/SQL Block, der sich während des Programmablaufes nicht verändert.
DECLARE konstantennameCONSTANTNUMBER(3):=10;
Die Wertzuweisung einer Konstante muss direkt bei der Deklaration erfolgen.
Benutzerdefinierte Datentypen
[Bearbeiten | Quelltext bearbeiten ]Benutzerdefinierte Datentypen werden definiert mit Hilfe von:
typedatentypisrecord(feld1typ1[:=xyz],feld2typ2[:=xyz],...,feldntypn[:=xyz]);
Beispiel:
declare typet_adresseisrecord( hausnameadresse.hausname%type, strasseadresse.strasse%type, hausnummeradresse.hausnummer%type, postleitzahladresse.postleitzahl%type); v_adresset_adresse; begin selecthausname,strasse,hausnummer,postleitzahlintov_adressefromadressewhererownum=1; end;
Das Beispielprogramm definiert einen eigenen Datentyp mit Namen t_adresse
, welcher die Felder hausname
, strasse
, hausnummer
und postleitzahl
enthält.
Mit diesem Datentyp wird eine Variable v_adresse
definiert, welche mit einem Datensatz aus der Tabelle adresse
gefüllt wird.
Mittels Punktnotation kann auf die Attribute zurückgegriffen werden
v_adresse.hausname:='Nollenburgerweg 115';
Schleifen
[Bearbeiten | Quelltext bearbeiten ]Schleifen wiederholen die in ihrem Rumpf enthaltenen Anweisungen.
Loop-Schleife (Basisschleife)
[Bearbeiten | Quelltext bearbeiten ]loop ... exitwhenBEDINGUNG; endloop;
Die loop
-Schleife wiederholt die in ihrem Körper enthaltenen Anweisungen. Sie kann durch ein exit when
gefolgt von einer Abbruchbedingung beendet werden.
Beachte: Auch wenn die Bedingung für das exit
erfüllt ist, werden die Anweisungen, die im Schleifenkörper vor der exit
-Anweisung stehen, mindestens einmal ausgeführt.
While-Schleife
[Bearbeiten | Quelltext bearbeiten ]whileBedingungloop ... endloop;
Die while
-Schleife wiederholt die in ihrem Körper enthaltenen Anweisungen, so lange die Bedingung in ihrem Kopf erfüllt ist.
Beachte: Sollte die Bedingung im Kopf nicht erfüllt sein, werden die Anweisungen im Schleifenkörper nie ausgeführt.
For-Schleife
[Bearbeiten | Quelltext bearbeiten ]forv_counterin1..10loop ... endloop;
Die for
-Schleife zählt eine Indexvariable von einem festgelegten Startwert bis zu einem festgelegten Endwert. Der kleinere Wert steht immer links, der größere immer rechts. Gibt man das Schlüsselwort REVERSE
nach dem IN
an, so wird vom größeren zum kleineren Wert heruntergezählt.
Beachte: Auch hierbei muss der kleinere Wert links und der größere Wert rechts stehen.
begin foriinreverse1..5loop dbms_output.put_line(to_char(i)); endloop; end;
5 4 3 2 1
Hinweis: Wenn Sie beim Arbeiten mit SQL*Plus die erwarteten Zahlen 5 bis 1 nicht sehen, müssen Sie vorher die Ausgabe einschalten.
setserveroutputon
Cursor-For-Schleife
[Bearbeiten | Quelltext bearbeiten ]forRecord-Indexin(SelectMitarbeiter_NummerfromPersonaltabelle) loop ... endloop;
Die Cursor for
-Schleife öffnet automatisch den Cursor, liest die Datensätze ein und schließt den Cursor wieder.
Alternativ dazu kann das SELECT
-Statement des Cursors auch vorher definiert werden, um es mehrfach zu verwenden bzw. um die Darstellung übersichtlicher zu gestalten (besonders bei längeren/komplexeren Abfragen von Vorteil).
cursorcursor_mitarbeiteris SelectMitarbeiter_NummerfromPersonaltabelle; forRecord-Indexincursor_mitarbeiter loop ... endloop;
Der Zugriff auf die Mitarbeiter-Nummer innerhalb der FOR
-Schleife erfolgt mit dem Verbindungsoperator .
:
Record-Index.Mitarbeiter_Nummer
Bedingungen
[Bearbeiten | Quelltext bearbeiten ]Mit Hilfe von Bedingungen kann man auf verschiedene Situationen unterschiedlich reagieren.
IF-THEN-ELSE
[Bearbeiten | Quelltext bearbeiten ]declare v_landwelt.land%type; begin dbms_output.enable(20000); selectlandintov_landfromwelt whererownum=1; ifv_land=39then dbms_output.put_line('Land ist 39'); elsifv_land=49then dbms_output.put_line('Land ist 49'); else dbms_output.put_line('Land unbekannt'); endif; end;
if
prüft, ob eine Bedingung erfüllt ist. Ist die Bedingung erfüllt, wird der Code zwischen if
und end if
ausgeführt, ansonsten wird er übersprungen. Optional kann mit elsif
eine weitere Bedingung mit zugehörigem Code angegeben werden, der ausgeführt wird, falls diese Bedingung erfüllt ist. Zu guter Letzt kann man ein allgemeines else
angeben, dessen Code ausgeführt wird, wenn keine der vorangegangenen Bedingungen erfüllt waren.
Bedingungsstrukturen kann man zudem mittels des CASE
-Statements ausdrücken.
CASE-WHEN
[Bearbeiten | Quelltext bearbeiten ]DECLARE v_landwelt.land%TYPE; BEGIN DBMS_OUTPUT.enable(20000); SELECTlandINTOv_landFROMwelt WHEREROWNUM=1; CASEWHENv_land=39THENDBMS_OUTPUT.put_line('Land ist 39'); WHENv_land=49THENDBMS_OUTPUT.put_line('Land ist 49'); WHENv_land=59THENDBMS_OUTPUT.put_line('Land ist 59'); ELSEDBMS_OUTPUT.put_line('Land unbekannt'); ENDCASE; END;
Vereinfachte Form für reine Wertelisten:
DECLARE v_landwelt.land%TYPE; BEGIN DBMS_OUTPUT.enable(20000); SELECTlandINTOv_landFROMwelt WHEREROWNUM=1; CASEv_land WHEN39THENDBMS_OUTPUT.put_line('Land ist 39'); WHEN49THENDBMS_OUTPUT.put_line('Land ist 49'); WHEN59THENDBMS_OUTPUT.put_line('Land ist 59'); ELSEDBMS_OUTPUT.put_line('Land unbekannt'); ENDCASE; END;
Exception-Handling
[Bearbeiten | Quelltext bearbeiten ]Es gibt zwei Arten von Exceptions:
- vordefinierte Exceptions und
- benutzerdefinierte Exceptions,
deren Handling analog ist.
Vordefinierte Exceptions
[Bearbeiten | Quelltext bearbeiten ]Exceptions werden automatisch von PL/SQL ausgelöst, wenn Fehler bei der Arbeit mit Datenbankobjekten (Tabellen, Views, Packages u. ä.) oder Programmierfehler (bspw. Division durch Null) bei der Abarbeitung des Programms auftreten. Es gibt in PL/SQL 20 Exceptions mit vordefinierten Namen. Jede Exception hat einen Fehlercode, der aus den Buchstaben ORA- und 5 Ziffern besteht. Typische Exceptions dieser Art sind
no_data_found (ORA-01403) – Eine SELECT-Anfrage liefert eine leere Datenmenge
too_many_rows (ORA-01422) – Eine SELECT-Anfrage liefert eine Datenmenge mit mehr als einem Satz, an einer Stelle, an der nur ein einzelner Satz als Ergebnis der Anfrage erwartet wurde.
Benutzerdefinierte Exceptions
[Bearbeiten | Quelltext bearbeiten ]Für die Behandlung logischer Programmfehler können eigene Exceptions in der Form
<exception_name>exception; pragmaexception_init(<exception_name>,-<exception_number>);
definiert und durch das Kommando
raise<exception_name>;
ausgelöst werden.
Exceptionblock
[Bearbeiten | Quelltext bearbeiten ]Der Exceptionblock dient dazu, alle Exceptions des dazugehörigen Ausführungsteiles abzufangen. Es besteht damit die Möglichkeit, nach einer Exception eine individuelle Fehlerbehandlung anzuschließen. Zum einen kann der Fehler nach dem Abfangen behandelt werden, danach kann im Programm weitergearbeitet werden; zum anderen kann die Exception an den umschließenden Block weitergereicht werden. Falls die Exception bis zum äußersten Block propagiert wird und dort keine entsprechende Fehlerbehandlung definiert wurde, führt dies zu einem unkontrollierten Abbruch des Programms.
Der generelle Aufbau eines Exceptionblocks ist folgender:
begin -- Programmcode der eine Exception auslösen kann Ausführungsteil ... exception when<exception_name_1>then -- Exceptionbehandlung für die Exception <exception_name_1> Ausführungsteil ... when<exception_name_n>then -- Exceptionbehandlung für die Exception <exception_name_n> Ausführungsteil whenothersthen -- Exceptionbehandlung für alle restlichen, nicht erwarteten Exceptions Ausführungsteil end;
Der when others
-Zweig ist optional; er fängt alle bis dahin im Exceptionblock nicht behandelten Exceptions ab. Fehlt dieser Zweig, werden unbehandelte Exceptions implizit an den umschließenden Block weitergereicht. Soll eine Exception explizit weitergereicht werden, muss der Ausführungsteil mit der Programmzeile raise <exception_name>;
enden.
Vergleich mit T-SQL
[Bearbeiten | Quelltext bearbeiten ]PL/SQL ist trotz oberflächlicher Ähnlichkeiten grundsätzlich anders als Transact-SQL. Bei der Übernahme von Quellcode handelt es sich daher in der Regel um eine nicht ganz einfache Arbeit. Nicht nur auf Grund der Unterschiede in den Feature-Sets der beiden Sprachen,[1] sondern auch wegen der sehr deutlichen Unterschiede, wie Oracle und SQL Server mit der Steuerung der Parallelität und dem Locking umgehen. Es gibt jedoch Software-Tools, die die Übernahme erleichtern können, zum Beispiel Oracle Translation Scratch Editor[2] und SwisSQL.[3]
Vergleichbare Möglichkeiten der Programmierung mit anderen Datenbank-Management-Systemen
[Bearbeiten | Quelltext bearbeiten ]- PL/pgSQL in der Open-Source-Datenbank PostgreSQL
- SQL-PL für Adabas
- SQL PL für Db2
- Transact-SQL (TSQL) ist die entsprechende Programmiersprache für RDBMS von Sybase und Microsoft
- Stored Procedures in MySQL ab Version 5
Weblinks
[Bearbeiten | Quelltext bearbeiten ]Einzelnachweise
[Bearbeiten | Quelltext bearbeiten ]- ↑ vyaskn.tripod.com.
- ↑ Scratchlauncher Oracle Scratchlauncher.
- ↑ swissql.com.