Oracle PL/SQL – Kontrollstrukturen

Fach: Informationstechnologie – Datenbanksysteme
Schulstufe: 12. Schulstufe – HTL Informatik
Voraussetzungen: PL/SQL Einführung, anonymer Block, Variablen
Autor: HTL Pinkafeld – IF/IT



1. IF – Einfache Verzweigung

1.1 Syntax

IF bedingung THEN
    -- Anweisungen, wenn Bedingung TRUE
END IF;

1.2 Beispiel

DECLARE
    v_sal emp.sal%TYPE;
BEGIN
    SELECT sal INTO v_sal FROM emp WHERE empno = 7369;

    IF v_sal < 1500 THEN
        DBMS_OUTPUT.PUT_LINE('Gehalt unter 1500 – Klasse: Einsteiger');
    END IF;
END;
/

1.3 IF–ELSE

DECLARE
    v_note NUMBER := 3;
BEGIN
    IF v_note <= 2 THEN
        DBMS_OUTPUT.PUT_LINE('Bestanden mit Auszeichnung');
    ELSE
        DBMS_OUTPUT.PUT_LINE('Bestanden');
    END IF;
END;
/

2. IF–ELSIF–ELSE / END IF – Mehrfachverzweigung

2.1 Syntax

IF bedingung1 THEN
    ...
ELSIF bedingung2 THEN
    ...
ELSIF bedingung3 THEN
    ...
ELSE
    ...
END IF;

Achtung: Oracle schreibt ELSIF (kein zweites E – kein ELSEIF!)

2.2 Beispiel: Notenbewertung

DECLARE
    v_punkte  NUMBER := 78;
    v_note    NUMBER;
    v_text    VARCHAR2(20);
BEGIN
    IF    v_punkte >= 91 THEN v_note := 1; v_text := 'Sehr Gut';
    ELSIF v_punkte >= 76 THEN v_note := 2; v_text := 'Gut';
    ELSIF v_punkte >= 61 THEN v_note := 3; v_text := 'Befriedigend';
    ELSIF v_punkte >= 51 THEN v_note := 4; v_text := 'Genügend';
    ELSE                       v_note := 5; v_text := 'Nicht Genügend';
    END IF;

    DBMS_OUTPUT.PUT_LINE(v_punkte || ' Punkte → Note ' || v_note || ' (' || v_text || ')');
END;
/

2.3 NULL in Bedingungen

Wenn eine Variable NULL ist, ist jeder Vergleich mit ihr NULL (weder TRUE noch FALSE):

DECLARE
    v_x NUMBER := NULL;
BEGIN
    IF v_x = 5 THEN        -- NULL = 5 → NULL → Zweig wird NICHT ausgeführt
        DBMS_OUTPUT.PUT_LINE('Gleich 5');
    ELSIF v_x IS NULL THEN  -- Korrekte Prüfung auf NULL
        DBMS_OUTPUT.PUT_LINE('v_x ist NULL');
    END IF;
END;
/

3. CASE – Auswahl

3.1 Einfaches CASE (Simple CASE)

Vergleicht einen Ausdruck mit konkreten Werten:

DECLARE
    v_tag NUMBER := TO_NUMBER(TO_CHAR(SYSDATE, 'D')); -- 1=Sonntag, 2=Montag ...
    v_name VARCHAR2(20);
BEGIN
    CASE v_tag
        WHEN 1 THEN v_name := 'Sonntag';
        WHEN 2 THEN v_name := 'Montag';
        WHEN 3 THEN v_name := 'Dienstag';
        WHEN 4 THEN v_name := 'Mittwoch';
        WHEN 5 THEN v_name := 'Donnerstag';
        WHEN 6 THEN v_name := 'Freitag';
        WHEN 7 THEN v_name := 'Samstag';
        ELSE         v_name := 'Unbekannt';
    END CASE;

    DBMS_OUTPUT.PUT_LINE('Heute ist ' || v_name);
END;
/

3.2 Durchsuchtes CASE (Searched CASE)

Jede WHEN-Klausel enthält eine eigene Bedingung:

DECLARE
    v_gehalt NUMBER := 4500;
    v_klasse VARCHAR2(20);
BEGIN
    CASE
        WHEN v_gehalt < 2000 THEN v_klasse := 'Niedrig';
        WHEN v_gehalt < 4000 THEN v_klasse := 'Mittel';
        WHEN v_gehalt < 7000 THEN v_klasse := 'Hoch';
        ELSE                       v_klasse := 'Sehr hoch';
    END CASE;

    DBMS_OUTPUT.PUT_LINE('Gehaltsklasse: ' || v_klasse);
END;
/

3.3 CASE als Ausdruck (in SQL)

SELECT ename,
       sal,
       CASE
           WHEN sal < 1500 THEN 'Einsteiger'
           WHEN sal < 3000 THEN 'Fachkraft'
           ELSE                  'Senior'
       END AS gehaltsklasse
FROM   emp
ORDER  BY sal;

4. Einfache LOOP-Schleife

4.1 Syntax

LOOP
    -- Anweisungen
    EXIT WHEN bedingung;  -- oder: EXIT (unbedingt)
END LOOP;

4.2 Beispiel: Multiplikationstabelle

DECLARE
    v_i     NUMBER := 1;
    v_basis NUMBER := 7;
BEGIN
    LOOP
        DBMS_OUTPUT.PUT_LINE(v_basis || ' × ' || v_i || ' = ' || (v_basis * v_i));
        v_i := v_i + 1;
        EXIT WHEN v_i > 10;
    END LOOP;
END;
/

4.3 Endlosschleife vermeiden

Ohne EXIT WHEN läuft die Schleife für immer! Immer eine Abbruchbedingung definieren:

-- GEFÄHRLICH – läuft endlos:
LOOP
    NULL;  -- kein EXIT!
END LOOP;

-- RICHTIG:
LOOP
    v_i := v_i + 1;
    EXIT WHEN v_i > 100;
END LOOP;

5. WHILE-Schleife

5.1 Syntax

WHILE bedingung LOOP
    -- Anweisungen (werden ausgeführt, solange Bedingung TRUE)
END LOOP;

Die Bedingung wird vor jedem Durchlauf geprüft. Wenn sie beim ersten Mal FALSE ist, wird der Block nie ausgeführt.

5.2 Beispiel: Fakultät berechnen

DECLARE
    v_n      NUMBER := 10;
    v_fak    NUMBER := 1;
    v_zaehler NUMBER := 1;
BEGIN
    WHILE v_zaehler <= v_n LOOP
        v_fak     := v_fak * v_zaehler;
        v_zaehler := v_zaehler + 1;
    END LOOP;

    DBMS_OUTPUT.PUT_LINE(v_n || '! = ' || v_fak);
END;
/

5.3 Vergleich LOOP vs. WHILE

Merkmal Einfache LOOP WHILE
Prüfzeitpunkt Am Ende (EXIT WHEN) Am Anfang
Mindestdurchläufe 1 0
Typischer Einsatz Wenn mindestens ein Durchlauf sicher Wenn 0 Durchläufe möglich

6. Numerische FOR-Schleife

6.1 Syntax

FOR zaehlvariable IN [REVERSE] untergrenze..obergrenze LOOP
    -- Anweisungen
END LOOP;

Die Zählvariable wird automatisch deklariert und verwaltet. Sie muss nicht im DECLARE-Abschnitt deklariert werden!

6.2 Vorwärts und Rückwärts

BEGIN
    -- Vorwärts: 1, 2, 3, 4, 5
    FOR i IN 1..5 LOOP
        DBMS_OUTPUT.PUT(i || ' ');
    END LOOP;
    DBMS_OUTPUT.NEW_LINE;

    -- Rückwärts: 5, 4, 3, 2, 1
    FOR i IN REVERSE 1..5 LOOP
        DBMS_OUTPUT.PUT(i || ' ');
    END LOOP;
    DBMS_OUTPUT.NEW_LINE;
END;
/

6.3 Beispiel: Zinseszins-Tabelle

DECLARE
    v_kapital   NUMBER := 10000;
    v_zinssatz  NUMBER := 0.035;  -- 3.5 %
BEGIN
    DBMS_OUTPUT.PUT_LINE('Jahr | Kapital');
    DBMS_OUTPUT.PUT_LINE('-----|--------');
    FOR jahr IN 1..10 LOOP
        v_kapital := v_kapital * (1 + v_zinssatz);
        DBMS_OUTPUT.PUT_LINE(
            LPAD(jahr, 4) || ' | ' || TO_CHAR(v_kapital, 'FM999,990.00') || ' €'
        );
    END LOOP;
END;
/

6.4 FOR mit dynamischen Grenzen

Die Grenzen können Ausdrücke sein, werden aber einmal beim Schleifenstart ausgewertet:

DECLARE
    v_von NUMBER := 5;
    v_bis NUMBER := 15;
BEGIN
    FOR i IN v_von..v_bis LOOP
        DBMS_OUTPUT.PUT(i || ' ');
    END LOOP;
    DBMS_OUTPUT.NEW_LINE;
END;
/

7. Cursor-FOR-Schleife (Vorschau)

Die Cursor-FOR-Schleife (vollständig im Kapitel „Cursor") iteriert automatisch über alle Zeilen einer Abfrage:

BEGIN
    FOR r IN (SELECT ename, sal FROM emp WHERE deptno = 20 ORDER BY sal DESC) LOOP
        DBMS_OUTPUT.PUT_LINE(r.ename || ': ' || r.sal);
    END LOOP;
END;
/

Vorteil: Kein explizites OPEN/FETCH/CLOSE nötig – PL/SQL erledigt das automatisch.


8. EXIT und CONTINUE

8.1 EXIT – Schleife sofort verlassen

DECLARE
    v_summe NUMBER := 0;
BEGIN
    FOR i IN 1..1000 LOOP
        v_summe := v_summe + i;
        EXIT WHEN v_summe > 100;  -- Bricht ab, sobald Summe > 100
    END LOOP;
    DBMS_OUTPUT.PUT_LINE('Summe: ' || v_summe);
END;
/

8.2 CONTINUE – Iteration überspringen

CONTINUE springt direkt zum nächsten Schleifendurchlauf (ab Oracle 11g):

BEGIN
    FOR i IN 1..10 LOOP
        CONTINUE WHEN MOD(i, 2) = 0;  -- Gerade Zahlen überspringen
        DBMS_OUTPUT.PUT(i || ' ');     -- Nur ungerade: 1 3 5 7 9
    END LOOP;
    DBMS_OUTPUT.NEW_LINE;
END;
/

8.3 Verschachtelte Schleifen mit Labels

Labels erlauben das gezielte Verlassen einer äußeren Schleife:

BEGIN
    <<aeussere_schleife>>
    FOR i IN 1..5 LOOP
        FOR j IN 1..5 LOOP
            EXIT aeussere_schleife WHEN i = 3 AND j = 3;  -- Beide Schleifen verlassen
            DBMS_OUTPUT.PUT('(' || i || ',' || j || ') ');
        END LOOP;
        DBMS_OUTPUT.NEW_LINE;
    END LOOP aeussere_schleife;
    DBMS_OUTPUT.PUT_LINE('Fertig.');
END;
/

9. GOTO und Labels

9.1 GOTO (mit Vorsicht verwenden)

GOTO springt zu einem Label im selben Block. Kann den Code schwer lesbar machen – in Ausnahmefällen nützlich:

DECLARE
    v_i NUMBER := 1;
BEGIN
    <<schleife_start>>
    IF v_i <= 5 THEN
        DBMS_OUTPUT.PUT_LINE('Iteration: ' || v_i);
        v_i := v_i + 1;
        GOTO schleife_start;
    END IF;
END;
/

Empfehlung: GOTO nach Möglichkeit vermeiden und stattdessen strukturierte Schleifen verwenden.

9.2 NULL-Anweisung als Platzhalter

NULL ist eine legale Anweisung, die nichts tut. Nützlich als Platzhalter:

BEGIN
    IF 1 = 2 THEN
        NULL;  -- Absichtlich leer – syntaktisch erforderlich
    END IF;
END;
/

10. Zusammenfassung und Ausblick

10.1 Übersicht der Kontrollstrukturen

Struktur Zweck Syntax
IF ... END IF Einfache Verzweigung IF b THEN ... END IF
IF ... ELSIF ... ELSE Mehrfachverzweigung IF b1 THEN ... ELSIF b2 THEN ...
CASE ... END CASE Mehrfachauswahl CASE x WHEN v THEN ...
LOOP ... END LOOP Bedingte Schleife mit EXIT WHEN
WHILE ... LOOP Kopfgesteuerte Schleife prüft vor jedem Durchlauf
FOR i IN a..b Zählschleife Zähler automatisch verwaltet
CONTINUE Iteration überspringen ab Oracle 11g
EXIT Schleife verlassen mit oder ohne Bedingung

10.2 Häufige Fehler

Fehler Problem
ELSEIF statt ELSIF Syntaxfehler – Oracle kennt nur ELSIF
Zählvariable im DECLARE deklariert FOR-Zähler ist implizit – Neudeklaration erzeugt Konflikte
Fehlendes END IF / END LOOP Syntaxfehler
NULL in Bedingung vergessen IF x = NULL ist nie TRUE – IS NULL verwenden!

10.3 Ausblick

Das nächste Kapitel behandelt Cursor – die Möglichkeit, mehrere Zeilen aus einer SQL-Abfrage zeilenweise zu verarbeiten:

Vorheriges ThemaEinführung & Grundstruktur Nächstes ThemaCursor