Cours SQL ORACLE – 07-05 : EXCEPTION Partie 1
Les exceptions sont des erreurs liées à notre programme qu’on gère de telles façons à ne pas avoir une erreur d’exécution dans notre programme. Pour utiliser les exceptions, la syntaxe à suivre est comme suit:
BEGIN
[programme susceptible de générera une erreur]
EXCEPTION WHEN
[erreur susceptible d'être générée]
THEN
[action à faire dans le cas d'erreur]
END;
Deux type d’exception existe:
- Exceptions définies par le système
- Exceptions définies par l’utilisateur
Dans ce cours nous allons voir les exceptions définies par le système. Le schéma utilisé pour les exemple est le schéma SCOTT.
Il existe plusieurs exception définie par Oracle. Nous n’allons pas tous les voir de ce cours, par contre on verra que ceux qui sont les plus utilisés:
- NO_DATA_FOUND
Cette exception est utilisée lorsque nous voulons stocker dans une variable la valeur d’un champ d’une table par une requête, et que la requête ne retourne aucune valeur. ATTENTION: cela ne veut pas dire que la valeur retournée est NULL.
Exécutons le programme ci-dessous:
DECLARE
VAR_ENAME VARCHAR2(50);
BEGIN
VAR_ENAME := '';
SELECT ENAME INTO VAR_ENAME FROM EMP WHERE EMPNO = 7788;
DBMS_OUTPUT.PUT_LINE('VAR_ENAME = ' || VAR_ENAME);
END;
Dans notre exemple le résultat obtenu sera:
VAR_ENAME = SCOTT
L’exécution n’a pas généré d’erreur puisque l’employé 7788 existe bien. Modifions maintenant notre requête de telle sorte à ne pas avoir de résultat dans notre requête:
DECLARE
VAR_ENAME VARCHAR2(50);
BEGIN
VAR_ENAME := '';
SELECT ENAME INTO VAR_ENAME FROM EMP WHERE EMPNO = 7788 AND 1 = 2;
DBMS_OUTPUT.PUT_LINE('VAR_ENAME = ' || VAR_ENAME);
END;
Le résultat est :
Rapport d'erreur :
ORA-01403: aucune donnée trouvée
ORA-06512: à ligne 6
01403. 00000 - "no data found"
Ce qui est normal puisque la requête ne retourne aucune valeur dons on ne peut pas affecter aucune valeur à notre variable VAR_ENAME.
Utilisons l’exception NO_DATA_FOUND et vérifions le résultat:
DECLARE
VAR_ENAME VARCHAR2(50);
BEGIN
VAR_ENAME := '';
BEGIN
SELECT ENAME INTO VAR_ENAME FROM EMP WHERE EMPNO = 7788 AND 1 = 2;
EXCEPTION WHEN NO_DATA_FOUND THEN
VAR_ENAME := 'Pas de donnée';
END;
DBMS_OUTPUT.PUT_LINE('VAR_ENAME = ' || VAR_ENAME);
END;
Le résultat maintenant est :
VAR_ENAME = Pas de donnée
Le programme s’est bien terminé sans aucune erreur.
Dans l’exemple suivant, nous allons récupérer une variable NULL et nous allons voir que l’exception ne se déclenche pas vu que la requête retourne bien une valeur mais qui est vide:
DECLARE
VAR_COMM NUMBER;
BEGIN
VAR_COMM := NULL;
BEGIN
SELECT COMM INTO VAR_COMM FROM EMP WHERE EMPNO = 7788;
EXCEPTION WHEN NO_DATA_FOUND THEN
VAR_COMM := 0;
END;
DBMS_OUTPUT.PUT_LINE('VAR_COMM = ' || VAR_COMM);
END;
Résultat:
VAR_COMM =
- TOO_MANY_ROWS
Au contraire de NO_DATA_FOUND, TOO_MANY_ROWS se déclenche lorsque la requête retourne plus d’une ligne. Rappelons que l’expression INTO dans une requête SQL n’attend qu’une et une seul valeur.
Exemple:
DECLARE
VAR_ENAME VARCHAR2(50);
BEGIN
VAR_ENAME := '';
SELECT ENAME INTO VAR_ENAME FROM EMP WHERE EMPNO = 7788;
DBMS_OUTPUT.PUT_LINE('VAR_ENAME = ' || VAR_ENAME);
END;
L’erreur suivante va se déclencher puis que la requête en question retourne plusieurs résultats. Le programme est donc en échec :
ORA-01422: l'extraction exacte ramène plus que le nombre de lignes demandé
ORA-06512: à ligne 6
01422. 00000 - "exact fetch returns more than requested number of rows"
*Cause: The number specified in exact fetch is less than the rows returned.
*Action: Rewrite the query or change number of rows requested
On va utiliser maintenant l’exception TOO_MANY_ROWS est voir le résultat:
DECLARE
VAR_ENAME VARCHAR2(50);
BEGIN
VAR_ENAME := '';
BEGIN
SELECT ENAME INTO VAR_ENAME FROM EMP WHERE JOB = 'ANALYST';
EXCEPTION WHEN TOO_MANY_ROWS THEN
VAR_ENAME := 'Plus qu''une ligne';
END;
DBMS_OUTPUT.PUT_LINE('VAR_ENAME = ' || VAR_ENAME);
END;
Résultat:
VAR_ENAME = Plus qu'une ligne
- OTHERS
L’exception OTHERS, comme son nom l’indique, permet de gérer n’importe quelle autre erreur déclenchée par notre programme. On peut l’utiliser, par exemple, lors d’insertion dans une table une clé primaire déjà utilisée.
Exemple :
DECLARE
VAR_ENAME VARCHAR2(50); BEGIN
UPDATE EMP SET ENAME = 'TEST' WHERE EMPNO = 7698; INSERT INTO EMP VALUES(7698, 'BLAKE', 'MANAGER', 7839, TO_DATE('01/05/1981', 'DD/MM/YYYY'), 2850, NULL, 30); COMMIT; EXCEPTION WHEN OTHERS THEN DBMS_OUTPUT.PUT_LINE('Erreur dans le programme'); ROLLBACK; SELECT ENAME INTO VAR_ENAME FROM EMP WHERE EMPNO = 7698; DBMS_OUTPUT.PUT_LINE('VAR_ENAME = ' || VAR_ENAME); END;
Le résultat de l’exécution sera :
Erreur dans le programme
VAR_ENAME = BLAKE
Lorsque l’erreur s’est déclenchée sur le INSERT, le programme s’est redirigé directement vers l’exception. Parmi les actions de cette exception, le ROOLBACK a annulé le premier UPDATE du coup l’ancienne valeur de ENAME est resté inchangée.
Il existe deux variable ORACLE qui donnent des détails de l’erreur rencontrée. Ces deux variable sont SQLCODE qui retourne le code erreur ORACLE et SQLERRM le libellé de l’erreur.
Nous allons reprendre l’exemple précédent en intégrant ces deux paramètres :
DECLARE
VAR_ENAME VARCHAR2(50); ECODE NUMBER; EMESG VARCHAR2(200); BEGIN
UPDATE EMP SET ENAME = 'TEST' WHERE EMPNO = 7698; INSERT INTO EMP VALUES(7698, 'BLAKE', 'MANAGER', 7839, TO_DATE('01/05/1981', 'DD/MM/YYYY'), 2850, NULL, 30, NULL); COMMIT; EXCEPTION WHEN OTHERS THEN ECODE := SQLCODE; EMESG := SQLERRM; DBMS_OUTPUT.PUT_LINE('Erreur dans le programme.'); DBMS_OUTPUT.PUT_LINE('Code Erreur : ' || ECODE); DBMS_OUTPUT.PUT_LINE('Libellé Erreur : ' || EMESG); ROLLBACK; SELECT ENAME INTO VAR_ENAME FROM EMP WHERE EMPNO = 7698; DBMS_OUTPUT.PUT_LINE('VAR_ENAME = ' || VAR_ENAME); END;
Le résultat de l’exécution sera :
Erreur dans le programme.
Code Erreur : -1
Libellé Erreur : ORA-00001: violation de contrainte unique (SCOTT.PK_EMP)
VAR_ENAME = BLAKE
Vous pouvez remarquer dans l’exemple précédent, qu’on peut faire une exception sur tout le programme entre le BEGIN et le END de tout le bloc PL/SQL. L’exception se déclenchera lorsque l’une des commandes du bloc générera une erreur.
Comme précédemment mentionné, il existe d’autre exception système comme ZERO_DIVIDE qui se déclenche lorsqu’on divise sur 0.
Vous pouvez aussi imbriquer les exceptions les unes les autres comme montre l’exemple suivant :
DECLARE
VAR_ENAME VARCHAR2(50);
BEGIN
VAR_ENAME := '';
BEGIN
SELECT ENAME INTO VAR_ENAME FROM EMP WHERE JOB = 'MANAGER';
EXCEPTION WHEN TOO_MANY_ROWS THEN
BEGIN
SELECT ENAME INTO VAR_ENAME FROM EMP WHERE JOB = 'PRESIDENT'; EXCEPTION WHEN OTHERS THEN VAR_ENAME := 'Personne'; END; END; DBMS_OUTPUT.PUT_LINE('VAR_ENAME = ' || VAR_ENAME); END;
Résultat:
VAR_ENAME = KING
Ou bien vous pouvez, dans la même section d’exception, faire plusieurs cas d’exception :
DECLARE
VAR_ENAME VARCHAR2(50);
BEGIN
VAR_ENAME := '';
BEGIN
SELECT ENAME INTO VAR_ENAME FROM EMP WHERE JOB = 'MANAGER';
EXCEPTION
WHEN TOO_MANY_ROWS THEN
VAR_ENAME := 'Plus qu''un';
WHEN NO_DATA_FOUND THEN
VAR_ENAME := 'Aucun';
WHEN OTHERS THEN VAR_ENAME := SQLERRM; END;
DBMS_OUTPUT.PUT_LINE('VAR_ENAME = ' || VAR_ENAME);
END;
Résultat:
VAR_ENAME = Plus qu'un