Inhaltsverzeichnis
Oracle PL/SQL – Exceptions (Fehlerbehandlung)
Fach: Informationstechnologie – Datenbanksysteme
Schulstufe: 12. Schulstufe – HTL Informatik
Voraussetzungen: PL/SQL Einführung, Kontrollstrukturen, Cursor
Autor: HTL Pinkafeld – IF/IT
1. Was sind Exceptions?
1.1 Definition
Eine Exception (Ausnahme) ist ein Laufzeitfehler, der den normalen Programmablauf unterbricht. PL/SQL bietet einen strukturierten Mechanismus, um solche Fehler abzufangen und darauf zu reagieren, ohne das Programm abstürzen zu lassen.
BEGIN
-- Normaler Programmfluss
...
-- Fehler tritt auf (z.B. ORA-01403)
↓
EXCEPTION
WHEN NO_DATA_FOUND THEN ← Gezielter Handler
...
WHEN OTHERS THEN ← Globaler Handler
...
END;
1.2 Ohne Exception-Handling
BEGIN
-- Wenn kein Mitarbeiter mit empno=9999 → ORA-01403
SELECT ename INTO v_name FROM emp WHERE empno = 9999;
DBMS_OUTPUT.PUT_LINE(v_name);
END;
/
-- Ergebnis: ORA-01403: no data found → Programm bricht ab
1.3 Mit Exception-Handling
DECLARE
v_name VARCHAR2(10);
BEGIN
SELECT ename INTO v_name FROM emp WHERE empno = 9999;
DBMS_OUTPUT.PUT_LINE(v_name);
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('Mitarbeiter nicht gefunden – kein Fehler!');
END;
/
-- Programm läuft sauber durch
2. Vordefinierte Oracle-Exceptions
2.1 Häufig verwendete Exceptions
| Exception | ORA-Fehler | Auslöser |
|---|---|---|
NO_DATA_FOUND |
ORA-01403 | SELECT INTO findet 0 Zeilen |
TOO_MANY_ROWS |
ORA-01422 | SELECT INTO findet > 1 Zeile |
ZERO_DIVIDE |
ORA-01476 | Division durch Null |
DUP_VAL_ON_INDEX |
ORA-00001 | Unique-Constraint verletzt |
VALUE_ERROR |
ORA-06502 | Typkonvertierung / Längenfehler |
INVALID_NUMBER |
ORA-01722 | Ungültige Zahl-Konvertierung |
INVALID_CURSOR |
ORA-01001 | Cursor-Operation auf ungültigem Cursor |
CURSOR_ALREADY_OPEN |
ORA-06511 | Cursor bereits geöffnet |
NOT_LOGGED_ON |
ORA-01012 | Keine aktive DB-Verbindung |
PROGRAM_ERROR |
ORA-06501 | Interner PL/SQL-Fehler |
ROWTYPE_MISMATCH |
ORA-06504 | Inkompatible Cursor-/Variablentypen |
STORAGE_ERROR |
ORA-06500 | Speicherproblem |
TIMEOUT_ON_RESOURCE |
ORA-00051 | Timeout beim Warten auf Ressource |
LOGIN_DENIED |
ORA-01017 | Ungültiger Benutzername/Passwort |
2.2 Beispiele für häufige Exceptions
DECLARE
v_erg NUMBER;
v_name VARCHAR2(5);
BEGIN
-- ZERO_DIVIDE
v_erg := 100 / 0;
EXCEPTION
WHEN ZERO_DIVIDE THEN
DBMS_OUTPUT.PUT_LINE('Fehler: Division durch Null!');
END;
/
DECLARE
v_name VARCHAR2(5) := 'Pinkafeld'; -- 9 Zeichen in 5-Zeichen-Variable
BEGIN
NULL;
EXCEPTION
WHEN VALUE_ERROR THEN
DBMS_OUTPUT.PUT_LINE('Wert zu lang für die Variable!');
END;
/
3. Der EXCEPTION-Abschnitt
3.1 Struktur
EXCEPTION
WHEN exception_name1 THEN
-- Handler für exception_name1
WHEN exception_name2 OR exception_name3 THEN
-- Handler für zwei Exceptions gleichzeitig
WHEN OTHERS THEN
-- Alles andere
3.2 Mehrere Handler
DECLARE
v_empno emp.empno%TYPE := &empno; -- Eingabe in SQL*Plus
v_row emp%ROWTYPE;
BEGIN
SELECT * INTO v_row FROM emp WHERE empno = v_empno;
DBMS_OUTPUT.PUT_LINE('Name: ' || v_row.ename);
DBMS_OUTPUT.PUT_LINE('Gehalt: ' || v_row.sal);
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('Mitarbeiter ' || v_empno || ' nicht gefunden.');
WHEN TOO_MANY_ROWS THEN
DBMS_OUTPUT.PUT_LINE('Mehrere Treffer – WHERE-Klausel präzisieren!');
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Unbekannter Fehler: ' || SQLERRM);
END;
/
3.3 Exception im Schleifenkontext
Nach einer Exception verlässt PL/SQL den aktuellen Block. Um Schleifen weiterzuführen, müssen Blöcke verschachtelt werden:
BEGIN
FOR r IN (SELECT empno FROM emp WHERE deptno = 20) LOOP
BEGIN -- Innerer Block fängt den Fehler
-- Hier irgendeine kritische Operation
IF r.empno = 7788 THEN
RAISE ZERO_DIVIDE; -- Simulierter Fehler
END IF;
DBMS_OUTPUT.PUT_LINE('Verarbeitet: ' || r.empno);
EXCEPTION
WHEN ZERO_DIVIDE THEN
DBMS_OUTPUT.PUT_LINE('Fehler bei ' || r.empno || ' – weiter...');
END;
END LOOP;
END;
/
4. OTHERS – Globaler Fänger
4.1 WHEN OTHERS als Sicherheitsnetz
WHEN OTHERS fängt alle nicht explizit behandelten Fehler ab:
DECLARE
v_val NUMBER;
BEGIN
v_val := TO_NUMBER('abc'); -- Ungültige Konvertierung
EXCEPTION
WHEN INVALID_NUMBER THEN
DBMS_OUTPUT.PUT_LINE('Ungültige Zahl eingegeben.');
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Fehlercode: ' || SQLCODE);
DBMS_OUTPUT.PUT_LINE('Fehlermeldung: ' || SQLERRM);
END;
/
4.2 Best Practice: OTHERS nie schweigen lassen
-- SCHLECHT: Fehler werden verschluckt
EXCEPTION
WHEN OTHERS THEN NULL;
-- GUT: Fehler protokollieren, dann weiterwerfen
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Fehler: ' || SQLERRM);
RAISE; -- Exception weitergeben an den aufrufenden Block
5. SQLCODE und SQLERRM
5.1 SQLCODE
SQLCODE gibt den numerischen Fehlercode zurück:
0→ kein Fehler- negative Zahl → Oracle-Fehler (z.B.
-1403für NO_DATA_FOUND) +100→ NO_DATA_FOUND in einigen Kontexten
5.2 SQLERRM
SQLERRM gibt die zugehörige Fehlermeldung zurück. Kann auch mit einem Fehlercode aufgerufen werden:
DECLARE
v_code NUMBER;
v_message VARCHAR2(500);
BEGIN
SELECT sal / 0 INTO v_code FROM dual;
EXCEPTION
WHEN OTHERS THEN
v_code := SQLCODE;
v_message := SQLERRM;
DBMS_OUTPUT.PUT_LINE('Code: ' || v_code);
DBMS_OUTPUT.PUT_LINE('Meldung: ' || v_message);
-- Fehlermeldung für bekannte Codes nachschlagen:
DBMS_OUTPUT.PUT_LINE(SQLERRM(-1403)); -- → ORA-01403: no data found
END;
/
6. Benutzerdefinierte Exceptions
6.1 Deklaration und Auslösung
Eigene Exceptions werden im DECLARE-Abschnitt deklariert und mit RAISE ausgelöst:
DECLARE
-- Eigene Exception deklarieren
e_ungültiges_gehalt EXCEPTION;
e_kein_manager EXCEPTION;
v_sal emp.sal%TYPE := -500;
BEGIN
-- Geschäftsregel prüfen
IF v_sal < 0 THEN
RAISE e_ungültiges_gehalt; -- Eigene Exception auslösen
END IF;
DBMS_OUTPUT.PUT_LINE('Gehalt OK: ' || v_sal);
EXCEPTION
WHEN e_ungültiges_gehalt THEN
DBMS_OUTPUT.PUT_LINE('Fehler: Gehalt darf nicht negativ sein!');
WHEN e_kein_manager THEN
DBMS_OUTPUT.PUT_LINE('Fehler: Kein Manager für diese Abteilung.');
END;
/
6.2 Praxisbeispiel: Geschäftsregeln validieren
DECLARE
e_min_gehalt EXCEPTION;
e_max_stunden EXCEPTION;
v_gehalt NUMBER := 1200;
v_stunden NUMBER := 55;
c_min_sal CONSTANT NUMBER := 1700;
c_max_h CONSTANT NUMBER := 50;
BEGIN
IF v_gehalt < c_min_sal THEN
RAISE e_min_gehalt;
END IF;
IF v_stunden > c_max_h THEN
RAISE e_max_stunden;
END IF;
DBMS_OUTPUT.PUT_LINE('Daten gültig.');
EXCEPTION
WHEN e_min_gehalt THEN
DBMS_OUTPUT.PUT_LINE('Gehalt unter Mindestlohn (' || c_min_sal || ' €)!');
WHEN e_max_stunden THEN
DBMS_OUTPUT.PUT_LINE('Überschreitung der Maximalstunden (' || c_max_h || 'h)!');
END;
/
7. RAISE_APPLICATION_ERROR
7.1 Benutzerdefinierte Fehlernummern
Mit RAISE_APPLICATION_ERROR können eigene ORA-Fehlermeldungen mit benutzerdefinierten Nummern erzeugt werden. Der Fehlercode muss im Bereich -20000 bis -20999 liegen:
PROCEDURE gehalt_pruefen (p_sal NUMBER) IS
BEGIN
IF p_sal < 0 THEN
RAISE_APPLICATION_ERROR(
-20001,
'Gehalt darf nicht negativ sein. Eingabe: ' || p_sal
);
ELSIF p_sal > 50000 THEN
RAISE_APPLICATION_ERROR(
-20002,
'Gehalt überschreitet das Maximum von 50.000. Eingabe: ' || p_sal
);
END IF;
END;
/
7.2 Aufruf und Behandlung
BEGIN
gehalt_pruefen(-100);
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('Fehler ' || SQLCODE || ': ' || SQLERRM);
-- Ausgabe: Fehler -20001: ORA-20001: Gehalt darf nicht negativ sein. Eingabe: -100
END;
/
7.3 Vergleich: RAISE vs. RAISE_APPLICATION_ERROR
| Merkmal | RAISE | RAISE_APPLICATION_ERROR |
|---|---|---|
| Fehlercode | Oracle-intern oder PL/SQL | -20000 bis -20999 (benutzerdefiniert) |
| Fehlermeldung | Vordefiniert | Frei definierbar |
| Im SQLERRM sichtbar | Ja | Ja |
| Gibt Kontrolle ab | Ja | Ja |
| Typischer Einsatz | Interne Exceptions | API-Fehler für aufrufende Schichten |
8. PRAGMA EXCEPTION_INIT
8.1 ORA-Fehler einer Exception zuordnen
Mit PRAGMA EXCEPTION_INIT kann einem Oracle-Fehlercode eine benannte Exception zugewiesen werden:
DECLARE
e_deadlock EXCEPTION;
PRAGMA EXCEPTION_INIT(e_deadlock, -60); -- ORA-00060: deadlock detected
e_fk_verletzt EXCEPTION;
PRAGMA EXCEPTION_INIT(e_fk_verletzt, -2292); -- ORA-02292: integrity constraint violated
BEGIN
DELETE FROM dept WHERE deptno = 10; -- Hat noch Mitarbeiter!
EXCEPTION
WHEN e_fk_verletzt THEN
DBMS_OUTPUT.PUT_LINE('Abteilung kann nicht gelöscht werden – hat noch Mitarbeiter!');
WHEN e_deadlock THEN
DBMS_OUTPUT.PUT_LINE('Deadlock erkannt – Transaktion zurückgerollt.');
END;
/
8.2 Wichtige ORA-Fehlercodes
| ORA-Code | Beschreibung |
|---|---|
| ORA-00001 | Unique Constraint verletzt |
| ORA-00060 | Deadlock erkannt |
| ORA-01400 | NULL-Wert für NOT NULL-Spalte |
| ORA-02291 | FK-Referenz nicht gefunden (Elternteil fehlt) |
| ORA-02292 | FK-Abhängigkeit vorhanden (Kind existiert noch) |
| ORA-04091 | Table is mutating (Trigger-Problem) |
9. Exception-Weiterleitung und Scope
9.1 Exceptions in verschachtelten Blöcken
BEGIN
BEGIN -- Innerer Block
RAISE NO_DATA_FOUND;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('Innerer Block: gefangen');
RAISE; -- Weiterwerfen an äußeren Block
END;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('Äußerer Block: auch gefangen');
END;
/
9.2 Exception-Sichtbarkeit
Benutzerdefinierte Exceptions sind nur im Block sichtbar, in dem sie deklariert wurden:
BEGIN
DECLARE
e_lokal EXCEPTION;
BEGIN
RAISE e_lokal;
EXCEPTION
WHEN e_lokal THEN
DBMS_OUTPUT.PUT_LINE('Lokal gefangen');
END;
-- RAISE e_lokal; -- FEHLER: e_lokal hier nicht sichtbar
END;
/
9.3 Transaktionssicherheit in Exception-Handlern
DECLARE
v_empno NUMBER := 9001;
BEGIN
INSERT INTO emp (empno, ename, deptno, sal, hiredate, job)
VALUES (v_empno, 'TESTUSER', 10, 2500, SYSDATE, 'CLERK');
UPDATE dept SET dname = 'INVALID' WHERE deptno = 999; -- Kein Effekt
COMMIT;
DBMS_OUTPUT.PUT_LINE('Transaktion erfolgreich.');
EXCEPTION
WHEN OTHERS THEN
ROLLBACK; -- Alle DML dieser Transaktion zurückrollen
DBMS_OUTPUT.PUT_LINE('Fehler – Rollback durchgeführt: ' || SQLERRM);
END;
/
10. Zusammenfassung und Ausblick
10.1 Exception-Typen im Überblick
| Typ | Deklaration | Auslösung | Beispiel |
|---|---|---|---|
| Vordefiniert | Automatisch | Automatisch durch Oracle | NO_DATA_FOUND |
| Nicht benannt | Automatisch | Automatisch durch Oracle | ORA-00904 |
| Benutzerdefiniert | EXCEPTION im DECLARE |
RAISE |
e_ungültiges_gehalt |
| Mit PRAGMA | EXCEPTION + PRAGMA EXCEPTION_INIT |
Automatisch | ORA-02292 benannt |
| Anwendungsfehler | Keine | RAISE_APPLICATION_ERROR |
-20001 |
10.2 Checkliste gutes Exception-Handling
- ✅ Spezifische Exceptions vor
WHEN OTHERSbehandeln - ✅
WHEN OTHERS THEN NULLvermeiden – immer protokollieren - ✅
ROLLBACKin Fehlerhandlern bei DML - ✅
RAISEnutzen, um Fehler weiterzugeben - ✅
RAISE_APPLICATION_ERRORfür sinnvolle API-Fehler - ✅ Bei Schleifen: Innere Blöcke verwenden, damit Schleife weiterläuft
10.3 Ausblick
Das nächste Kapitel behandelt gespeicherte Prozeduren und Funktionen – wiederverwendbare PL/SQL-Programme in der Datenbank:
- Unterschied zwischen Prozedur und Funktion
- Parameter-Modi: IN, OUT, IN OUT
- Lokale vs. gespeicherte Subprogramme
- Aufrufen aus SQL und PL/SQL