Einführung in PL/SQL

Werbung
8
88
Einführung in PL/SQL
Das Speichern und Auslesen von Informationen ist nur ein Teil jeder „echten“ Applikation. Auch die einfachsten Programme müssen Aktionen durchführen, die sich mit
SQL gar nicht oder nur sehr schwer umsetzen ließen. Denken Sie nur daran, wie aufwändig die Berechnungen sind, die jedes Jahr vom Finanzamt vorgenommen werden
müssen, um die korrekten Steuern zu berechnen! OK, vielleicht möchten Sie sich lieber ein anderes Beispiel vorstellen. Auf jeden Fall ist SQL alleine nicht sehr nützlich.
8.1
Was ist PL/SQL?
Sie werden sich fragen, warum SQL nicht über Fähigkeiten verfügt, die es Ihnen ermöglichen, aufwändigere Berechnungen mit den Daten durchzuführen. Das ist zum
Teil historisch bedingt: SQL entstand als Datenbank-Abfragesprache (Structured
Query Language) und wurde weiterentwickelt und optimiert für genau diesen Zweck:
Datenbanken abzufragen. Verschiedene Datenbank-Hersteller haben sich auf bestimmte SQL-Standards geeinigt, nicht aber darauf, wie den Benutzern weitergehende
SQL-orientierte Programmierumgebungen zur Verfügung gestellt werden sollten. Daher präsentiert jeder Datenbank-Hersteller seine proprietäre oder semi-proprietäre
Lösung. Oracle bezeichnet seine Lösung als PL/SQL. Dies steht für „Programming
Language for SQL“.
In diesem Kapitel werden Sie in die Grundlagen von PL/SQL eingeführt. Sie werden
den Unterschied zwischen SQL, SQL*Plus und PL/SQL kennen lernen. Weiterhin
werden Sie erste einfache PL/SQL-Prozeduren schreiben sowie Funktionen, die
grundlegende PL/SQL-Konstrukte wie Variablen, Schleifen und Cursor verwenden.
Dann werden Sie den wichtigen Bereich der Fehlerbehandlung kennen lernen, damit
dem Benutzer verständliche Mitteilungen gemacht werden können.
Wenn Sie erst in diesem Kapitel mit dem Lesen des Buchs begonnen und noch keine
der Übungen aus den vorigen Kapiteln nachgespielt haben, sollten Sie die Beispielta-
280
8 Einführung in PL/SQL
bellen aus den vorigen Kapiteln erstellen, bevor Sie die Übungen aus diesem Kapitel
nachvollziehen können. Dazu dienen die folgenden SQL-Befehle:
DROP
DROP
DROP
DROP
DROP
TABLE
TABLE
TABLE
TABLE
TABLE
plsql101_purchase;
plsql101_product;
plsql101_person;
plsql101_old_item;
plsql101_purchase_archive;
CREATE TABLE plsql101_person (
person_code VARCHAR2(3) PRIMARY KEY,
first_name VARCHAR2(15),
last_name
VARCHAR2(20),
hire_date
DATE
)
;
CREATE INDEX plsql101_person_name_index
ON plsql101_person(last_name, first_name);
ALTER TABLE plsql101_person
ADD CONSTRAINT plsql101_person_unique UNIQUE (
first_name,
last_name,
hire_date
)
;
INSERT INTO plsql101_person VALUES
(’CA’, ’Charlotte’, ’Atlas’, ’01.02.02’);
INSERT INTO plsql101_person VALUES
(’GA’, ’Gerhard’, ’Anderson’, ’15.02.02’);
INSERT INTO plsql101_person VALUES
(’BB’, ’Bernd’, ’Barkenhagen’, ’28.02.02’);
INSERT INTO plsql101_person VALUES
(’LB’, ’Lars’, ’Baxter’, ’01.03.02’);
INSERT INTO plsql101_person VALUES (
’LN’, ’Lara’, ’Normann’, ’01.06.03’);
CREATE TABLE plsql101_product (
product_name
VARCHAR2(25) PRIMARY KEY,
product_price
NUMBER(4,2),
quantity_on_hand NUMBER(5,0),
last_stock_date DATE
)
;
ALTER TABLE plsql101_product ADD CONSTRAINT positive_quantity CHECK(
quantity_on_hand IS NOT NULL
AND
8.1 Was ist PL/SQL?
;
281
quantity_on_hand >= 0
)
INSERT INTO plsql101_product VALUES
(’Small Widget’, 99, 1, ’15.01.03’);
INSERT INTO plsql101_product VALUES
(’Medium Wodget’, 75, 1000, ’15.01.02’);
INSERT INTO plsql101_product VALUES
(’Chrome Phoobar’, 50, 100, ’15.01.03’);
INSERT INTO plsql101_product VALUES
(’Round Chrome Snaphoo’, 25, 10000, NULL);
INSERT INTO plsql101_product VALUES
(’Extra Huge Mega Phoobar +’,9.95,1234,’15.01.04’);
INSERT INTO plsql101_product VALUES (’Square Zinculator’,
45, 1, TO_DATE(’31. Dezember 2002, 23:30’,
’dd. Month YYYY, HH24:MI’)
)
;
INSERT INTO plsql101_product VALUES (
’Anodized Framifier’, 49, 5, NULL);
INSERT INTO plsql101_product VALUES (
’Red Snaphoo’, 1.95, 10, ’31.12.00’);
INSERT INTO plsql101_product VALUES (
’Blue Snaphoo’, 1.95, 10, ’30.12.01’)
;
CREATE TABLE plsql101_purchase (
product_name VARCHAR2(25),
salesperson
VARCHAR2(3),
purchase_date DATE,
quantity
NUMBER(4,2)
)
;
ALTER TABLE plsql101_purchase
ADD PRIMARY KEY (product_name,
salesperson,
purchase_date
)
;
ALTER TABLE plsql101_purchase ADD CONSTRAINT reasonable_date CHECK(
purchase_date IS NOT NULL
AND
TO_CHAR(purchase_date, ’YYYY-MM-DD’) >= ’2000-06-30’
)
;
282
8 Einführung in PL/SQL
ALTER TABLE plsql101_purchase
ADD CONSTRAINT plsql101_purchase_fk_product FOREIGN KEY
(product_name) REFERENCES plsql101_product;
ALTER TABLE plsql101_purchase
ADD CONSTRAINT plsql101_purchase_fk_person FOREIGN KEY
(salesperson) REFERENCES plsql101_person;
CREATE INDEX plsql101_purchase_product
ON plsql101_purchase(product_name);
CREATE INDEX plsql101_purchase_salesperson
ON plsql101_purchase(salesperson);
INSERT INTO plsql101_purchase VALUES
(’Small Widget’, ’CA’, ’14.07.03’, 1);
INSERT INTO plsql101_purchase VALUES
(’Medium Wodget’, ’BB’, ’14.07.03’, 75);
INSERT INTO plsql101_purchase VALUES
(’Chrome Phoobar’, ’GA’, ’14.07.03’, 2);
INSERT INTO plsql101_purchase VALUES
(’Small Widget’, ’GA’, ’15.07.03’, 8);
INSERT INTO plsql101_purchase VALUES
(’Medium Wodget’, ’LB’, ’15.07.03’, 20);
INSERT INTO plsql101_purchase VALUES
(’Round Chrome Snaphoo’, ’CA’, ’16.07.03’, 5);
INSERT INTO plsql101_purchase VALUES (
’Small Widget’, ’CA’, ’17.07.03’, 1)
;
UPDATE plsql101_product
SET
product_price = product_price * .9
WHERE product_name NOT IN (
SELECT DISTINCT product_name
FROM
plsql101_purchase
)
;
CREATE TABLE plsql101_old_item (
item_id
CHAR(20),
item_desc CHAR(25)
)
;
INSERT INTO plsql101_old_item VALUES
(’LA-101’, ’Can, Small’);
INSERT INTO plsql101_old_item VALUES
(’LA-102’, ’Can, Large’);
INSERT INTO plsql101_old_item VALUES
(’LA-103’, ’Bottle, Small’);
283
8.1 Was ist PL/SQL?
INSERT INTO plsql101_old_item VALUES
(’LA-104’, ’Bottle, Large’);
INSERT INTO plsql101_old_item VALUES
(’NY-101’, ’Box, Small’);
INSERT INTO plsql101_old_item VALUES
(’NY-102’, ’Box, Large’);
INSERT INTO plsql101_old_item VALUES
(’NY-103’, ’Shipping Carton, Small’);
INSERT INTO plsql101_old_item VALUES
(’NY-104’, ’Shipping Carton, Large’);
CREATE TABLE plsql101_purchase_archive (
product_name VARCHAR2(25),
salesperson
VARCHAR2(3),
purchase_date DATE,
quantity
NUMBER(4,2)
)
;
INSERT INTO plsql101_purchase_archive VALUES
(’Round Snaphoo’, ’BB’, ’21.06.01’, 10);
INSERT INTO plsql101_purchase_archive VALUES
(’Large Harflinger’, ’GA’, ’22.06.01’, 50);
INSERT INTO plsql101_purchase_archive VALUES
(’Medium Wodget’, ’LB’, ’23.06.01’, 20);
INSERT INTO plsql101_purchase_archive VALUES
(’Small Widget’, ’ZZ’, ’24.06.02’, 80);
INSERT INTO plsql101_purchase_archive VALUES
(’Chrome Phoobar’, ’CA’, ’25.06.02’, 2);
INSERT INTO plsql101_purchase_archive VALUES
(’Small Widget’, ’JT’, ’26.06.02’, 50);
8.1.1
Beschreibung von PL/SQL
PL/SQL bietet Möglichkeiten, die es Ihnen erlauben, Informationen auf komplexe Art
und Weise zu verarbeiten. Jede Nacht werden Sie die Zusammenfassung der täglichen
Geschäftsvorgänge in eine Übersichtstabelle transferieren wollen – PL/SQL-Pakete
können Ihnen dabei helfen. Möchten Sie wissen, ob Sie zusätzliche Lieferungen anfordern müssen, um große Bestellungen bedienen zu können – PL/SQL bietet Trigger, die
Sie benachrichtigen, sobald eine Bestellung eingegeben wird, die bestimmte, vorgegebene Grenzen überschreitet. Sie können gespeicherte PL/SQL-Prozeduren nutzen, um
die Leistung Ihrer Mitarbeiter zu berechnen und den Bonus festzulegen. Eine nette
kleine PL/SQL-Funktion kann die Steuersätze für einen Angestellten ermitteln.
PL/SQL stellt Ihnen alle Datenmanipulationsmöglichkeiten, Cursor-Kontrollen und
Transaktionskontrollbefehle von SQL zur Verfügung, wie auch sämtliche SQL-Funktionen und -Operatoren. Damit behalten Sie bei der Manipulation von Daten in Ora-
284
8 Einführung in PL/SQL
cle die volle Flexibilität und Kontrolle. Außerdem unterstützt PL/SQL alle SQLDatentypen. Dadurch verringert sich die Notwendigkeit, Daten zu konvertieren, die
zwischen Ihrer Applikation und der Datenbank ausgetauscht werden. PL/SQL stellt
auch „Dynamic SQL“ zur Verfügung, eine fortgeschrittene Programmiertechnik, mit
der Ihre Applikationen flexibler und anpassbarer werden. Ihre Programme können
SQL-Befehle zur Datendefinition, Datenkontrolle und Transaktionskontrolle „on the
fly“ zur Laufzeit erstellen und ausführen lassen.
Bevor wir mehr über einige dieser Fähigkeiten erfahren, werde ich Ihnen erläutern, wie
PL/SQL, SQL und SQL*Plus miteinander verbunden sind.
8.1.2
Who’s Who in SQL, PL/SQL und SQL*Plus
Stellen Sie sich ein Restaurant vor. Sie gehen hinein und werden (hoffentlich) von einem gut ausgebildeten Ober erwartet. Sie schauen sich die Speisekarte an und geben
eine Bestellung auf. Der Ober notiert Ihre Bestellung und bringt sie in die Küche. Die
Küche ist groß – es gibt viele Köche und Hilfsköche. Sie können viele Speisen sehen –
gekocht, vorgegart und ungekocht – die in der Küche abgestellt sind. Es gibt auch Personen mit unterschiedlichen Aufgaben: Sie holen die Vorräte aus dem Lager, bereiten
bestimmte Gänge vor (zum Beispiel nur Suppen oder Salate) und so weiter. Ihrer
Menüfolge entsprechend gibt der Ober die Bestellung an verschiedene Köche weiter.
Einfache Gänge werden von nur einem Koch zubereitet, während aufwändigere Menüs die Hilfe eines Assistenten bei der Zubereitung erfordern oder sogar mehrere Köche. Zusätzlich gibt es „Standardbestellungen“ – ein Ober teilt einem Koch nur „Pizza
Hawaii“ mit – während andere Bestellungen individuell zusammengestellt sind und
eine genaue Liste der Zutaten erfordern.
Nun ändern wir das Szenario ein bisschen. Denken Sie an eine Oracle-Datenbank als
Küche des Restaurants, in der SQL*Plus als Ober unsere Bestellungen – Skripte, Befehle oder Programme – an die Küche oder Datenbank weiterleitet. Innerhalb der Küche
gibt es zwei Köche: SQL und PL/SQL. Wie ein Ober weiß SQL*Plus, welche Bestellungen es selbst abwickeln kann und welche es an wen weiterleiten muss. Genau wie ein
Ober Ihnen ein Glas Wasser bringen kann, ohne den Chefkoch zu belästigen, kann
SQL*Plus die Zeilenlänge auf Ihrem Bildschirm anpassen, ohne auf die Datenbank zugreifen zu müssen.
Die Befehle oder Programme, die Sie am SQL*Plus-Prompt eingeben und ausführen,
sind so etwas wie Ihre individuell zusammengestellte Pizza. Bei solchen Bestellungen
müssen die Köche jedes Mal ein bisschen nachdenken. Wie auch der Koch ein Rezept
für eine Käse-Pizza in seinem Gehirn gespeichert hat, können Sie PL/SQL „Rezepte“
für Ihre Lieblingsgerichte speichern lassen. Diese gespeicherten PL/SQL-Elemente
werden Trigger, gespeicherte Funktionen und Pakete genannt. Sie werden bald mehr
über sie lernen.
285
8.1 Was ist PL/SQL?
Wie ich schon weiter oben erwähnte, benötigen einige Bestellungen mehr als einen
Koch, um sie zu bearbeiten. Die meisten der interessanteren und nützlicheren Datenbank-Applikationen, die Sie erstellen, werden SQL und PL/SQL zusammen einsetzen,
wobei Informationen zwischen beiden Bereichen ausgetauscht werden, um ein Skript
oder ein Programm auszuführen. In einem Restaurant wird die Bestellung nach der
Zubereitung von einem Ober an Ihren Tisch gebracht. In ähnlicher Weise werden die
Ergebnisse von SQL- und PL/SQL-Programmen an SQL*Plus (oder ein eigenes Frontend) zurückgeliefert, um sie dem Benutzer anzuzeigen.
8.1.3
Gespeicherte Prozeduren, Funktionen
und Trigger
PL/SQL-Prozeduren, Funktionen und Trigger helfen Ihnen dabei, komplexe Geschäftslogiken einfach und in modularer Form (das heißt, Stück für Stück, wobei die
einzelnen Stücke von anderen Elementen wiederverwendet werden können) zu erstellen. Beim Abspeichern auf dem Oracle-Server bietet das zwei direkte Vorteile: Sie können immer wieder mit vorhersagbaren Ergebnissen genutzt werden und sie lassen sich
deutlich schneller ausführen, da Server-Operationen wenig oder gar keinen Netzwerkverkehr erzeugen.
Gespeicherte Prozeduren
Eine gespeicherte Prozedur ist ein festgelegtes Set von Aktionen, die mit der Programmiersprache PL/SQL geschrieben wurden. Wenn eine Prozedur aufgerufen wird, führt
sie die enthaltenen Aktionen aus. Die Prozedur ist in der Datenbank abgespeichert, daher heißt sie „gespeicherte Prozedur“.
Eine gespeicherte Prozedur kann SQL-Befehle ausführen und Daten in Tabellen verändern. Sie kann dazu auch von anderen gespeicherten PL/SQL-Prozeduren, Funktionen oder Triggern aufgerufen werden. Eine gespeicherte Prozedur kann auch direkt
vom SQL*Plus-Prompt aus gestartet werden. Wenn Sie die nächsten Seiten lesen, werden Sie lernen, wie jede dieser Methoden zum Aufruf einer gespeicherten Prozedur
verwendet wird.
Eine Prozedur besteht aus zwei Teilen: der Spezifikation und dem Rumpf. Die Prozedur-Spezifikation enthält den Namen der Prozedur und eine Beschreibung der Einund Ausgabeparameter. Die Ein- und Ausgabeparameter werden formale Parameter
oder formale Argumente der Prozedur genannt. Wenn ein Aufruf einer Prozedur Kommandozeilen-Parameter oder andere Eingaben mit einschließt, werden diese Werte
konkrete Parameter oder konkrete Argumente genannt.
Betrachten wir nun ein paar Beispiele für Prozedur-Spezifikationen. (Denken Sie daran, dass die Spezifikation keinerlei Code enthält; sie gibt der Prozedur nur einen Namen und legt die Ein- und Ausgabeparameter fest, die die Prozedur verwenden kann.)
286
8 Einführung in PL/SQL
run_ytd_reports
Diese einfache Spezifikation enthält nur den Prozedurnamen. Sie hat keine Parameter.
increase_prices (percent_increase NUMBER)
Ein Wert kann an diese Prozedur weitergegeben werden, wenn sie aufgerufen wird. Innerhalb der Prozedur wird der Wert als PERCENT_INCREASE angesprochen. Beachten Sie, dass der Datentyp festgelegt wurde: NUMBER.
increase_salary_find_tax (increase_percent IN
NUMBER := 7,
sal
IN OUT NUMBER,
tax
OUT NUMBER
)
Hier haben wir eine Prozedur mit drei formalen Parametern. Das Wort „IN“ nach einem Parameternamen zeigt an, dass die Prozedur einen Eingabewert aus den Parametern nutzen kann, wenn sie aufgerufen wird. Das Wort „OUT“ nach einem
Parameternamen zeigt an, dass die Prozedur diesen Parameter nutzen kann, um
Werte an den Aufrufenden zurückzuliefern. Ein Parameter mit den Schlüsselwörtern
„IN OUT“ kann einen Wert in die Prozedur einbringen, aber auch als Rückgabewert
dienen.
Dem Parameter INCREASE_PERCENT wird in diesem Beispiel ein Standardwert von
7 zugewiesen, indem „:= 7“ nach dem Datentyp angefügt wird. Wenn nun die Prozedur ohne die Angabe einer prozentualen Erhöhung aufgerufen wird, wird sie die Gehälter um sieben Prozent erhöhen und die Steuern basierend auf den neuen Werten
berechnen.
Hinweis:
Datentypen in einer Prozedur können keine Größenangaben
enthalten. Sie können zum Beispiel festlegen, dass ein Parameter
vom Typ NUMBER ist, aber nicht vom Typ NUMBER(10, 2).
Der Prozedurrumpf ist ein Block mit PL/SQL-Code, über den Sie im nächsten Abschnitt dieses Kapitels einiges lernen werden.
Gespeicherte Funktionen
Eine PL/SQL-Funktion ist einer PL/SQL-Prozedur sehr ähnlich: Sie besitz eine Funktionsspezifikation und einen Funktionsrumpf. Der entscheidende Unterschied zwischen einer Prozedur und einer Funktion ist der, dass eine Funktion dafür gedacht ist,
einen Wert zurückzuliefern, der in einem größeren SQL-Befehl genutzt werden kann.
287
8.1 Was ist PL/SQL?
Stellen Sie sich zum Beispiel eine Funktion vor, die zum Berechnen der prozentualen
Differenz zwischen zwei Zahlen gedacht ist. Ohne den Code, der die Berechnung
durchführt, würde die Spezifikation so aussehen:
calc_percent(value_1 NUMBER,
value_2 NUMBER) return NUMBER
Diese Funktion akzeptiert zwei Zahlen als Eingabewerte, auf die intern mit VALUE_1
und VALUE_2 verwiesen wird. Nachdem der Rumpf der Funktion geschrieben wurde,
können Sie sie in einem SQL-Befehl wie folgt verwenden:
INSERT INTO employee VALUES (3000, CALC_PERCENT(300, 3000));
Trigger
Ein Trigger ist eine PL/SQL-Prozedur, die automatisch ausgeführt wird, sobald ein bestimmtes, vom Trigger definiertes Ereignis – das auslösende Ereignis – eintritt. Sie können Trigger schreiben, die ausgelöst werden, sobald ein INSERT-, UPDATE- oder
DELETE-Befehl auf eine Tabelle ausgeführt wird; wenn DDL-Befehle genutzt werden;
wenn sich ein Benutzer an- oder abmeldet, oder wenn die Datenbank startet, einen
Fehler meldet oder herunterfährt.
Trigger unterscheiden sich von PL/SQL-Prozeduren in drei Punkten:
n Sie können einen Trigger nicht aus Ihrem Code aufrufen. Trigger werden von
Oracle automatisch als Reaktion auf ein vorgegebenes Ereignis aufgerufen.
n Trigger enthalten keine Parameterliste.
n Die Spezifikation eines Triggers enthält andere Informationen als die für eine Prozedur.
Sie werden mehr über Trigger und ihre Verwendung im nächsten Kapitel lernen.
8.1.4
Gespeicherte Prozeduren und SQL-Skripte
Während SQL-Skripte auf der Festplatte Ihres Rechners gespeichert sind, werden gespeicherte Prozeduren innerhalb Ihrer Oracle-Datenbank abgelegt. Ein SQL-Skript
enthält eine Reihe von SQL-Befehlen, die nacheinander ausgeführt werden, wenn Sie
das Skript aufrufen. Eine gespeicherte Prozedur dagegen kann Befehle zur Ablaufkontrolle enthalten, die es ihr ermöglichen, einen bestimmten Teil des Codes immer wieder abzuarbeiten, zu einem anderen Code-Abschnitt zu verzweigen, wenn bestimmte
Situationen auftreten, und auf Fehler in der von Ihnen vorgegebenen Art und Weise
zu reagieren.
288
8 Einführung in PL/SQL
8.2
Struktur eines PL/SQL-Blocks
In diesem Abschnitt werden Sie einen einfachen PL/SQL-Block kennen lernen. Alles,
was in PL/SQL läuft, besteht aus Blöcken. Nachdem Sie sich mit dem PL/SQL-Block
vertraut gemacht haben, werden Sie im nächsten Abschnitt Beispiele für komplette
Prozeduren, Funktionen und Trigger gezeigt bekommen.
Ein PL/SQL-Block besteht aus vier Abschnitten: dem Kopf, einem optionalen Deklarationsabschnitt, dem Ausführungsabschnitt und einem optionalen Ausnahmeabschnitt.
Ein anonymer Block ist ein PL/SQL-Block ohne Kopf oder Namensabschnitt, daher
auch der Begriff „anonymer Block“. Anonyme Blöcke können unter SQL*Plus ausgeführt werden und in PL/SQL-Funktionen, Prozeduren und Triggern Verwendung finden. Denken Sie daran, dass PL/SQL-Prozeduren, Funktionen und Trigger selbst alle
aus PL/SQL-Blöcken bestehen. Das bedeutet, dass Sie einen PL/SQL-Block innerhalb
eines anderen PL/SQL-Blocks haben können. Sie werden mehr darüber weiter unten
in diesem Abschnitt lernen.
Vielleicht ist der beste Weg, einen PL/SQL-Block zu verstehen, ein Beispiel auszuführen. Geben Sie zunächst den folgenden Befehl ein, damit Informationen von Programmen in SQL*Plus ausgegeben werden.
set serveroutput on
Nun geben Sie den folgenden Code ein, um einen anonymen Block zu erstellen. Vergleichen Sie Ihre Ergebnisse mit Abbildung 8-1.
DECLARE
BEGIN
num_a NUMBER := 6;
num_b NUMBER;
num_b := 0;
num_a := num_a / num_b;
num_b := 7;
dbms_output.put_line(’ Wert von num_b ’ || num_b);
EXCEPTION
WHEN ZERO_DIVIDE
THEN
dbms_output.put_line(’Versuch, durch Null zu teilen’);
dbms_output.put_line(’ Wert von num_a ’ || num_a);
dbms_output.put_line(’ Wert von num_b ’ || num_b);
END;
/
8.2 Struktur eines PL/SQL-Blocks
289
Abbildung 8-1: Beispiel für einen anonymen PL/SQL-Block
8.2.1
Kopf
Der Kopf eines Blocks sieht abhängig davon, wozu er gehört, unterschiedlich aus. Erinnern Sie sich daran, dass Prozeduren, Funktionen, Trigger und anonyme Blöcke aus
PL/SQL-Blöcken bestehen. Tatsächlich hat jeder von ihnen einen PL/SQL-Block, der
den Rumpf darstellt. Dieser Rumpf-Block kann nun wiederum mehrere PL/SQL-Blöcke enthalten. Der Kopf dieses obersten Blocks einer Funktion, Prozedur oder eines
Triggers ist die Spezifikation für diese Funktion, Prozedur oder diesen Trigger. Bei anonymen Blöcken enthält der Kopf nur das Schlüsselwort DECLARE. Bezeichnete Blöcke enthalten im Kopf den Namen, der durch << und >> umschlossen wird, gefolgt
vom Schlüsselwort DECLARE, wie im Folgenden gezeigt:
<<just_a_label>>
DECLARE
Blockbezeichner erhöhen die Lesbarkeit des Codes. In einer Prozedur, die verschachtelte Blöcke verwendet (Blöcke innerhalb anderer Blöcke) können Sie sich auf ein Element in einem bestimmten Block beziehen, indem Sie vor den Namen des Elements
den Namen des Blocks setzen (zum Beispiel block_label.item_label).
290
8 Einführung in PL/SQL
8.2.2
Deklarationsabschnitt
Der Deklarationsabschnitt ist optional. Wenn er genutzt wird, beginnt er direkt nach
dem Kopf und endet mit dem Schlüsselwort BEGIN. Der Deklarationsabschnitt enthält die Deklarationen für PL/SQL-Variablen, Konstanten, Cursor, Exceptions, Funktionen und Prozeduren, die von den Ausführungs- und Ausnahmeabschnitten
verwendet werden. Alle Deklarationen von Variablen und Konstanten müssen angegeben werden, bevor die erste Funktions- oder Prozedurdeklaration aufgeführt ist. Sie
werden mehr über PL/SQL-Variablen und Konstanten im folgenden Abschnitt lernen.
Eine Deklaration teilt PL/SQL mit, dass es eine Variable, Konstante, Funktion, Prozedur oder einen Cursor so erstellen soll, wie es in der Deklaration festgelegt wurde.
Der Deklarationsabschnitt im Beispiel von Abbildung 8-1 auf Seite 289 fordert PL/SQL
dazu auf, zwei Variablen vom Typ NUMBER anzulegen, die die Namen Num_a und
Num_b erhalten sollen. Er weist der Variablen Num_a zudem noch den Standardwert
6 zu.
Wenn ein PL/SQL-Block abgearbeitet wurde, hören alle Deklarationen aus dessen Deklarationsabschnitt auf zu existieren. Elemente aus dem Deklarationsabschnitt eines
Blocks können nur innerhalb des gleichen Blocks verwendet werden. Daher gibt es
nach dem Durchlauf des Beispiel-Blocks in SQL*Plus auch keinerlei Möglichkeit
mehr, Num_a an eine andere PL/SQL-Prozedur weiterzugeben. Num_a und Num_b
verschwinden direkt nach der Beendigung des Blocks aus dem Blickfeld. Wenn Sie allerdings eine PL/SQL-Funktion oder -Prozedur innerhalb des Ausführungs- oder Ausnahmeabschnitts des Blocks aufrufen, können Sie ihnen Num_a oder Num_b als
konkrete Parameter mitgeben.
Langer Rede kurzer Sinn: Alles, was im Deklarationsabschnitt angelegt wird, ist das
Privateigentum des Blocks – es kann nur durch ihn genutzt werden und ist auch nur
für ihn sichtbar. Alles aus dem Deklarationsabschnitt des Blocks existiert nur solange
wie der Block selbst. Technisch gesprochen: Num_a und Num_b besitzen den Geltungsbereich des Blocks, in dem sie deklariert wurden. Der Geltungsbereich des Blocks
beginnt mit dem Anfang des Deklarationsabschnitts und endet mit dem Ende seines
Ausnahmeabschnitts.
8.2.3
Ausführungsabschnitt
Der Ausführungsabschnitt beginnt mit dem Schlüsselwort BEGIN und endet auf zwei
verschiedene Arten. Wenn es einen Ausnahmeabschnitt gibt, endet der Ausführungsabschnitt mit dem Schlüsselwort EXCEPTION. Wenn es keinen Ausnahmeabschnitt
gibt, endet er mit dem Schlüsselwort END, optional gefolgt vom Namen der Funktion
oder Prozedur, und einem Semikolon. Der Ausführungsabschnitt enthält einen oder
mehrere PL/SQL-Befehle, die ausgeführt werden, wenn der Block abläuft. Die Struktur des Ausführungsabschnitts sieht wie folgt aus:
8.2 Struktur eines PL/SQL-Blocks
291
BEGIN
einer oder mehrere PL/SQL-Befehle
[Ausnahmeabschnitt]
END [Name der Funktion oder Prozedur];
Der Ausführungsabschnitt des Beispielblocks enthält drei PL/SQL-Zuweisungsbefehle. Der Zuweisungsbefehl ist der am häufigsten verwendete Befehl im PL/SQL-Code.
Der erste Befehl weist Num_b den Wert 0 zu. Der Doppelpunkt, gefolgt von einem
Gleichheitszeichen, ist der Zuweisungsoperator. Er teilt PL/SQL mit, alles rechts von
ihm zu berechnen und das Ergebnis dem zuzuweisen, was sich links von ihm befindet.
Der zweite Befehl weist Num_a den Wert von Num_a geteilt durch Num_b zu. Beachten Sie, dass sich nach erfolgreicher Ausführung dieses Befehls der Wert von Num_a
geändert hat.
Der dritte Befehl weist Num_b den Wert 7 zu.
8.2.4
Ausnahmeabschnitt
Es ist möglich, dass während der Ausführung von PL/SQL-Anweisungen im Ausführungsabschnitt ein Fehler auftaucht, der es unmöglich macht, mit der Ausführung
fortzufahren. Diese Fehlerbedingungen werden Exceptions (oder Ausnahmen) genannt. Der Benutzer der Prozedur sollte über das Auftreten und den Grund einer Exception informiert werden. Vielleicht wollen Sie dem Benutzer eine sinnvolle
Fehlermeldung präsentieren, oder korrigierend eingreifen und versuchen, die Prozedur an der entsprechenden Stelle fortzuführen. Eventuell möchten Sie ja auch alle Änderungen an der Datenbank bis zum Auftreten des Fehlers rückgängig machen.
Für all diese Situationen stellt PL/SQL die Exception-Behandlung zur Verfügung. Exceptions sind für gut geschriebene Applikationen so wichtig, dass ich am Ende des Kapitels einen speziellen Abschnitt über sie angefügt habe, in dem Sie mehr darüber
erfahren können. Als Einführung sei hier die Struktur des Ausnahmeabschnitts aufgeführt:
EXCEPTION
WHEN exception_name
THEN
Aktionen, die beim Auftreten dieser Exception ausgeführt werden sollen
WHEN exception_name
THEN
Aktionen, die beim Auftreten dieser Exception ausgeführt werden sollen
292
8 Einführung in PL/SQL
Der Ausnahmeabschnitt beginnt mit dem Schlüsselwort EXCEPTION und endet am
Ende des Blocks. Für jede Exception gibt es eine Anweisung WHEN exception_name,
die angibt, was getan werden soll, wenn diese Exception auftritt. Unser Beispiel enthält
drei lustig aussehende Zeilen, die dafür sorgen, dass auf Ihrem SQL*Plus-Bildschirm
Text ausgegeben wird. Zum Verständnis ihrer Arbeitsweise sind allerdings weitere Informationen notwendig, die in Kapitel 9 gegeben werden. Das Paket DBMS_OUTPUT
und die Prozedur PUT_LINE sind Teil der Oracle-Datenbank; zusammen sorgen sie
dafür, dass auf Ihrem SQL*Plus-Bildschirm Zeile für Zeile Text ausgegeben wird.
Alle Befehle zwischen der Anweisung, die den Fehler auslöste, und dem Ende des Abschnitts werden ignoriert. Daher wird im Beispielblock die Zuweisung des Werts 7 an
die Variable Num_b nicht durchgeführt. Sie können dies kontrollieren, indem Sie sich
den Wert von Num_b anschauen, der vom Beispielcode ausgegeben wird.
Wenn eine Exception durch eine Anweisung im Ausnahmeabschnitt behandelt wird,
bezeichnen wir diese Aktion als Exception-Behandlung.
Das Erkennen eines aufgetretenen Fehlers, das Zuordnen der passendsten Exception
und das Ausführen entsprechender Schritte, um PL/SQL darüber zu informieren, welcher Teil des Ausnahmeabschnitts verwendet werden soll, bezeichnet man als das Auslösen einer Exception (raising an exception). Im Beispielcode wird die Exception von
PL/SQL selbst ausgelöst, da es einen Versuch feststellt, durch Null zu teilen. PL/SQL hat
einen vorgegebenen Namen für diese Exception – ZERO_DIVIDE. Häufig muss der
Fehler aber von Ihrem eigenen Code entdeckt werden, da PL/SQL dies nicht erkennt.
8.3
Eine einfache PL/SQL-Prozedur erstellen
Wir haben nun alle Zutaten, um zu versuchen, eine komplette PL/SQL-Prozedur zu
schreiben. Sie kennen PL/SQL-Blöcke und haben gelernt, wie die Spezifikation einer
Prozedur aussehen muss. Geben Sie einmal den folgenden Code ein.
CREATE PROCEDURE my_first_proc IS
greetings VARCHAR2(20);
BEGIN
greetings := ’Hallo Welt’;
dbms_output.put_line(greetings);
END my_first_proc;
/
Die Syntax für das Erstellen einer gespeicherten Prozedur lautet:
CREATE PROCEDURE procedure_specification IS procedure_body
In unserem Beispiel besteht die Spezifikation der Prozedur nur aus dem Namen, und
der Rumpf aus allem bis zum letzten Semikolon. Für Funktionen nutzen Sie statt des
Schlüsselworts PROCEDURE das Wort FUNCTION.
8.3 Eine einfache PL/SQL-Prozedur erstellen
293
CREATE FUNCTION function_specification IS function_body
Der Schrägstrich (/) teilt SQL*Plus mit, dass die Befehle nun abgearbeitet werden sollen. Sie können die gleiche Prozedur oder Funktion erneut erstellen, indem Sie den Befehl CREATE in CREATE OR REPLACE abwandeln. Damit wird die alte Definition
zerstört und duch die neue ersetzt. Wenn keine alte Definition vorhanden ist, wird
einfach eine neue angelegt.
CREATE OR REPLACE PROCEDURE procedure_specification IS procedure_body
Betrachten wir nun, wie diese Prozedur aus SQL*Plus heraus aufgerufen werden kann:
set serveroutput on
EXECUTE my_first_proc;
SERVEROUTPUT ON ermöglicht Ihnen, die ausgegebenen Zeilen zu betrachten. Der
Befehl EXECUTE führt dann die Prozedur aus. Sie können die Prozedur auch aus einem anonymen Block aufrufen, wie im Folgenden gezeigt wird. Vergleichen Sie Ihre
Ergebnisse mit denen in Abbildung 8-2.
BEGIN
END;
/
my_first_proc;
Abbildung 8-2: Eine einfache „Hallo Welt“-PL/SQL-Prozedur
294
8 Einführung in PL/SQL
8.3.1
Prozeduren und Funktionen aufrufen
Eine Prozedur oder Funktion kann formale Parameter mit Standardwerten enthalten
oder auch nicht. Tatsächlich muss sie gar keine formalen Parameter enthalten. Dem
jeweiligen Fall entsprechend ist die Aufrufkonvention unterschiedlich. Die folgenden
Punkte sind aber unabhängig von den Parametern gültig.
n Die Datentypen der konkreten Parameter müssen passen oder sollten wenigstens
von PL/SQL in die entsprechenden formalen Parameter konvertierbar sein.
n Konkrete Parameter müssen für alle formalen Parameter angegeben werden, die
keine Standardwerte haben.
Wenn Sie eine Funktion ohne Parameter aufrufen, können Sie den Namen der Funktion mit oder ohne Klammern angeben:
procedure_name();
oder
procedure_name;
Die gleiche Syntax wird beim Verwenden von Funktionen genutzt, nur dass innerhalb
eines Ausdrucks kein Semikolon angegeben werden darf.
Wenn eine Prozedur formale Parameter mit Standardwerten besitzt und diese sich alle
am Ende der Liste mit den formalen Parametern in der Prozedurspezifikation befinden, kann die Prozedur einfach ohne die Angabe der Werte für die letzten formalen
Parameter aufgerufen werden, für die Standardwerte existieren. Dies geht aber nur
dann, wenn für alle vorigen Parameter auch konkrete Werte mitgeliefert werden. Der
Aufruf sieht dann so aus:
procedure_name(actual_param1,
actual_param2,
...
actual_paramN);
N kann kleiner oder gleich der Anzahl der formalen Parameter dieser Prozedur sein,
muss aber größer oder gleich der Anzahl der formalen Parameter ohne Standardwerte
sein.
Wenn die formalen Parameter mit gegebenen Standardwerten nicht die letzten Parameter in der Spezifikation sind, oder wenn Sie vermeiden wollen, dass PL/SQL selbst
anhand der Reihenfolge herausfinden muss, welcher konkrete Wert welchem formalen Parameter zugeordnet werden soll, können Sie mit der folgenden Syntax PL/SQL
exakt mitteilen, welcher konkrete Parameter für welchen formalen Parameter genutzt
werden soll:
8.4 PL/SQL-Variablen und Konstanten
295
procedure_name(formal_param1 => actual_param1,
formal_param2 => actual_param2,
...
)
;
Dies wird als benannte Notation beim Aufruf von Funktionen und Prozeduren bezeichnet. Die vorige Notation dagegen heißt positionsabhängige Notation, da die Parameter über ihre Position in der Liste zugeordnet werden.
Die gleiche Art des Aufrufs ist auch für Funktionen gültig. Sie können aber in anderen
Ausdrücken auftauchen und haben dann kein Semikolon am Ende. Sie werden Beispiele für die benannte Notation im nächsten Abschnitt sehen. Es ist möglich, die beiden Notationen zu kombinieren, dann muss aber die positionsabhängige Liste im
Aufruf vor der benannten Liste angegeben werden.
8.4
PL/SQL-Variablen und Konstanten
Sie haben einige Beispiel für PL/SQL-Variablen im vorigen Abschnitt kennen gelernt.
Nun wollen wir sie uns genauer anschauen. Variablen sind prinzipiell Schachteln mit
Namensschildchen. Sie können Informationen oder Daten verschiedenen Typs enthalten. Abhängig von der Art der Daten, die sie aufbewahren können, haben sie unterschiedliche Datentypen, und um sie auseinanderhalten zu können, haben sie Namen.
Genauso, wie Öl in Flaschen und Mehl in Papiertüten aufbewahrt wird, speichert
PL/SQL Zahlen in Variablen des Datentyps NUMBER und Text in Variablen der Datentypen CHAR oder VARCHAR2. Gehen wir noch einen Schritt weiter: Stellen Sie
sich einen Kühlschrank in der Kantine Ihrer Firma vor. Er ist voller brauner Papiertüten mit Ihrem Lunch und dem Ihrer Kollegen. Wie finden Sie nun heraus, welches Ihrer ist? Genau! Ihr Lunchpaket ist beschriftet mit Ihrem Namen. Variablen haben auch
Namen, um Verwechslungen zu vermeiden. Wenn Ihr Lunch nur aus Bananen bestand, geben Sie nach ihrem Verzehr vielleicht die Schalen wieder in die braune Tüte.
Der Inhalt der Tüte hat sich also geändert. Genauso kann sich der Inhalt von Variablen
während der Ausführung von PL/SQL-Anweisungen ändern.
296
8 Einführung in PL/SQL
8.4.1
PL/SQL-Variablen deklarieren
Die Syntax für das Deklarieren einer Variable in PL/SQL lautet wie eine der beiden folgenden Zeilen:
variable_name data_type [ [NOT NULL] := default_value_expression];
variable_name data_type [ [NOT NULL] DEFAULT default_value_expression];
variable_name ist jeder gültige PL/SQL-Bezeichner. Ein gültiger PL/SQL-Bezeichner
muss folgende Bedingungen erfüllen:
n Er kann bis zu 30 Zeichen lang sein und darf keinerlei Leerzeichen oder Tabulatoren beinhalten.
n Er besteht aus Buchstaben, den Ziffern 0 bis 9, dem Unterstrich (_), Dollar ($)
oder dem Nummernzeichen (#).
n Er beginnt mit einem Buchstaben.
n Er darf kein reserviertes Wort in PL/SQL oder SQL sein, das eine spezielle Bedeutung für PL/SQL oder SQL hat. Ein Variablenname kann zum Beispiel nicht „BEGIN“ heißen. BEGIN teilt nämlich PL/SQL mit, dass hier der Anfang eines
PL/SQL-Blocks ist.
data_type ist jeder gültige SQL- oder PL/SQL-Datentyp. Im nächsten Abschnitt erhalten Sie weitere Informationen über Datentypen.
Die Verwendung von NOT NULL erfordert, dass die Variable immer einen Wert hat.
Wenn dies angegeben wurde, muss auch zwingend ein Standardwert mit angegeben
werden.
Wenn eine Variable angelegt wird, kann sie gleich mit einem Standardwert ausgestattet werden. Dies ist eine einfache Möglichkeit, Variablen Werte zuzuweisen.
Sie kennen bereits SQL-Datentypen – NUMBER, VARCHAR2 und DATE. PL/SQL
verfügt wie SQL über diese Datentypen, hat darüber hinaus aber noch weitere Datentypen, die SQL nicht bietet. Eine komplette Liste finden Sie in den PL/SQL-Referenzen
von Oracle.
8.4.2
PL/SQL-Konstanten deklarieren
Die Syntax für das Deklarieren einer Konstante lautet:
variable_name data_type CONSTANT := constant_value_expression;
Anders als Variablen muss Konstanten ein Wert mitgegeben werden, der während der
Lebenszeit der Konstanten auch nicht geändert werden kann. Konstanten sind sehr
nützlich, wenn Sie die Entwicklung großer und komplexer Applikationen sicherer und
8.4 PL/SQL-Variablen und Konstanten
297
„disziplinierter“ machen wollen. Wenn Sie zum Beispiel sicherstellen wollen, dass die
Daten, die einer PL/SQL-Prozedur mitgeteilt werden, sich von der Prozedur nicht ändern lassen, können Sie diese Daten zu Konstanten machen. Wenn die Prozedur dann
versucht, sie zu ändern, löst PL/SQL eine Exception aus.
8.4.3
Variablen Werte zuweisen
Es gibt drei verschiedene Wege, den Wert einer Variable zu ändern. Das Zuweisen eines gültigen Ausdrucks mit dem Zuweisungsoperator von PL/SQL ist der erste Weg.
Sie haben schon einige Beispiele dafür gesehen. Die Syntax lautet:
variable_name := expression;
Als zweite Möglichkeit kann eine Variable als konkreter Parameter für formale IN
OUT- oder OUT-Parameter an eine PL/SQL-Prozedur übergeben werden. Nachdem
die Prozedur abgearbeitet wurde, kann sich der Wert der Variablen geändert haben.
Das folgende Beispiel zeigt die benannte Notation beim Aufruf einer Prozedur. Schauen Sie sich für die Ausgabe Abbildung 8-3 auf Seite 298 an.
CREATE
IS
BEGIN
PROCEDURE hike_prices (old_price NUMBER,
percent_hike NUMBER := 5,
new_price OUT NUMBER)
new_price := old_price + old_price * percent_hike / 100;
END hike_prices;
/
Die folgende Prozedur zeigt, wie die Variablen ihren Wert ändern:
DECLARE
BEGIN
price_to_hike NUMBER(6,2) := 20;
hiked_price NUMBER(6,2) := 0;
dbms_output.put_line(’Preis vor hike_prices ’ || price_to_hike);
dbms_output.put_line(’hiked_price vor hike_prices ’ ||
hiked_price);
hike_prices (old_price => price_to_hike,
new_price => hiked_price);
dbms_output.put_line(’Preis nach hike_prices ’ || price_to_hike);
dbms_output.put_line(’hiked_price nach hike_prices ’ ||
hiked_price);
END;
/
298
8 Einführung in PL/SQL
Abbildung 8-3: PL/SQL-Variablen Werte zuweisen, indem sie als konkrete Parameter genutzt
werden
Der dritte Weg, um Variablen Werte zuzuweisen oder sie zu ändern, wird detaillierter
im nächsten Kapitel besprochen. Hier nur ein kleines Beispiel, zu dem Abbildung 8-4
auf Seite 299 das Ergebnis zeigt.
DECLARE
product_quant
NUMBER;
BEGIN
SELECT quantity_on_hand
INTO
product_quant
FROM
plsql101_product
WHERE
product_name = ’Small Widget’;
dbms_output.put_line (’Small Widget ’ || product_quant);
END;
/
product_quant wird der Wert zugewiesen, der der Anzahl der „Small Widgets“ entspricht.
8.5 Kontrollstrukturen in PL/SQL
299
Abbildung 8-4: Einer PL/SQL-Variablen einen Wert durch SQL zuweisen
8.4.4
Variablen verwenden
Variablen sind die grundlegenden Elemente von PL/SQL-Programmen. Sie werden
verwendet, um die Ergebnisse von Berechnungen zu speichern, um Werte aus Funktionsaufrufen zurückzuliefern, und als konkrete Parameter für Funktionen und Prozeduren und so weiter. Variablen sollen Ihre Applikation ordentlicher und lesbarer
machen, damit den Wartungsaufwand reduzieren und ein effizienteres Programm
schaffen.
Angenommen, Sie wollen einige Berechnungen mit der aktuellen Anzahl der „Small
Widgets“ durchführen – sie mit der Anzahl von vor drei Monaten oder der Anzahl der
„Medium Widgets“ vergleichen. Wenn Sie eine Variable zum Speichern des Werts
nutzen, vermeiden Sie die Verzögerungen, die entstehen, wenn Sie den Wert wieder
und wieder aus der Tabelle auslesen.
Wenn Sie Variablen sinnvoll benennen, wird Ihr Code leichter lesbar und verständlicher. Dieselben Prinzipien gelten auch, wenn Sie Variablen zum Speichern von Ergebnissen aus komplexen Berechnungen verwenden, anstatt die Berechnung im Code an
mehreren Stellen direkt auszuführen.
8.5
Kontrollstrukturen in PL/SQL
Häufig wollen Sie etwas tun, wenn eine Bedingung wahr ist, und etwas anderes, wenn
sie falsch ist. Wenn zum Beispiel eine Bestellung über einem gewissen Betrag liegt, sollen vielleicht fünf Prozent abgezogen werden, und sogar zehn Prozent, wenn sie über
einem anderen Betrag liegt. Diese Art von Logik mag innerhalb Ihrer Applikation erforderlich sein, wenn die abschließende Rechnung für Ihre Kunden ausgedruckt wird.
Herunterladen