Você está na página 1de 14

Universit Tunis El Manar Institut Suprieur dInformatique

Anne Universitaire 2011-2012

Matire : Systme de Gestion de Bases de Donnes Enseignant : R. ZAFRANI - I B. AYED

Niveau : 2me anne SIL Mars 2012

Cours n5 : Les curseurs et les exceptions PL/SQL

1. Prsentation des curseurs


Lune des plus importantes caractristiques de PL/SQL est la possibilit de manipuler les donnes ligne par ligne. SQL est en effet un langage de type tout ou rien. Il est impossible de tester ou de modifier de manire slective une ligne particulire dans un ensemble de lignes ramenes par un ordre SELECT. Lorsquon excute un ordre SQL partir de PL/SQL, Oracle alloue une zone de travail prive pour cet ordre. Les curseurs PL/SQL sont un mcanisme permettant de nommer cette zone de travail et de manipuler les donnes quelle contient. Un curseur PL/SQL permet de rcuprer et de traiter les donnes de la base dans un programme PL/SQL, ligne par ligne. Il existe deux sortes de curseurs : Les curseurs explicites : Ils sont crs et grs par lutilisateur pour traiter un ordre SELECT qui ramne plusieurs lignes. Le traitement du rsultat pourra se faire ligne par ligne. Les curseurs implicites : Ils sont gn rs automatiquement par le noyau pour toute requte SQL, mme pour ceux qui ne retournent quune ligne. Les curseurs implicites ont les inconvnients suivants : Ils sont moins performants que les curseurs explicites Ils sont plus sujets aux erreurs de donnes Ils laissent moins de contrle au programmeur

Pour les requtes qui renvoient plus dun enregistrement (mme celles qui renvoient un seul enregistrement), vous pouvez dclarer explicitement un curseur, ce qui permet de traiter individuellement les lignes retournes. Un programme PL/SQL ouvre un curseur, traite les enregistrements retourns par lordre SQL, puis ferme le curseur. Le curseur permet disoler lenregistrement courant dun jeu de rsultats. Les tapes dutilisation dun curseur explicite, pour traiter un ordre SELECT, sont les suivantes: Dclaration du curseur Ouverture du curseur Traitement des lignes Fermeture du curseur

Tout curseur explicite utilis dans un bloc PL/SQL doit obligatoirement tre dclar dans la section DECLARE du bloc, en prcisant son nom et lordre SQL associ. La syntaxe de dclaration dun curseur explicite est : CURSOR NOM_CURSEUR [(NOM_ARGUMENT TYPE :=VALEUR_DEFAUT [,])] IS REQUETE; La requte peut contenir tous les ordres SQL dinterrogation de donnes, y compris les oprateurs ensemblistes UNION , INTERSECT ou MINUS . Les types darguments sont les suivants : CHAR , NUMBER , DATE, BOOLEAN ; leur longueur nest pas spcifie. Le passage des valeurs des paramtres seffectue louverture du curseur. SQL> declare 2 CURSOR c_employ IS SELECT nom,prnom, salaire, commission 3 4 FROM employs ORDER BY nom;

Nous avons cr dans cet exemple, un curseur c_employ qui contient les colonnes nom, prnom, salaire, commission pour lensemble des enregistrements de la table employs. SQL> declare 2 CURSOR c_produit ( 3 4 5 6 v_no_Fournisseur Produit.no_Fournisseur%TYPE:=1, v_code_catgorie Produit.code_catgorie%TYPE :=1) IS SELECT nomproduit,prix_unitaire FROM produit WHERE no_Fournisseur = v_no_Fournisseur AND code_catgorie = v_code_catgorie;

Cet exemple expose la cration dun curseur c_produit contenant les colonnes nomproduit, prix_unitaire pour lensemble des produits du fournisseur et de la catgorie donns, par lintermdiaire des arguments v_no_Fournisseur et v_code_catgorie. * Remarque : Les expressions de calcul ou les fonctions SQL, qui se trouvent dans la clause SELECT de la requte du curseur, doivent comporter un alias pour pouvoir tre rfrences. SQL> declare 2 CURSOR c_somme_sal IS SELECT fonction, sum(salaire) total_salaire 3 4 FROM employs GROUP BY fonction;

2. Ouverture dun curseur :


Ds que vous ouvrez le curseur, lexcution de lordre SQL est lance. Cette phase douverture seffectue dans la section BEGIN du bloc : OPEN NOM_CURSEUR [(VALEUR_ARGUMENT [,])]; SQL> declare 2 CURSOR c_employ IS SELECT nom,prnom, salaire, commission 2

3 4 Begin 5

FROM employs ORDER BY nom;

open c_employ;

Les arguments spcifis lors de la dclaration du curseur sont dfinis lors de louverture du curseur. Chaque argument est affect a une seule valeur selon deux modles : - Association par position : Dans ce cas, chaque argument est remplac par la valeur occupant la mme position dans la liste. SQL> declare 2 CURSOR c_produit ( 3 4 v_no_Fournisseur Produit.no_Fournisseur%TYPE :=1, v_code_catgorie Produit.code_catgorie%TYPE :=1)

5 IS SELECT nomproduit,prix_unitaire FROM produit 6 7 WHERE no_Fournisseur = v_no_Fournisseur AND code_catgorie = v_code_catgorie;

8 begin 9 open c_produit(2);

Dans cet exemple, louverture comporte un seul argument v_no_Fournisseur affect 2. Largument v_code_catgorie ne figurant pas dans la dclaration, il est affect avec sa valeur par dfaut. Les arguments doivent tre renseignes obligatoirement sil ny a pas de valeur par dfaut dclare. Les arguments associs par position sont affects dans lordre de leur dclaration dans le curseur. Vous ne pouvez pas affecter le deuxime sans renseigner le premier. Association par nom : Dans ce cas, chaque argument peut tre indiqu dans un ordre quelconque en faisant apparatre la correspondance de faon explicite sous la forme : OPEN NOM_CURSEUR [(NOM_ARGUMENT => VALEUR_ARGUMENT[,])]; SQL> declare 2 CURSOR c_produit ( 3 4 v_no_Fournisseur Produit.no_Fournisseur%TYPE:=1, v_code_catgorie Produit.code_catgorie%TYPE :=1)

5 IS SELECT nomproduit,prix_unitaire FROM produit 6 7 WHERE no_Fournisseur = v_no_Fournisseur AND code_catgorie = v_code_catgorie;

8 begin 9 open c_produit(v_code_catgorie => 2);

3. Traitement des lignes dun curseur


Lordre OPEN a forc lexcution de lordre SQL associ au curseur. 3

Il faut maintenant rcuprer les lignes de lordre SELECT et les traiter une par une, en stockant la valeur de chaque colonne de lordre SQL dans une variable rceptrice. La commande FETCH permet de rcuprer un enregistrement et transfre les valeurs projets par lordre SELECT dans un enregistrement ou dans une liste de variables : FETCH NOM_CURSEUR {NOM_ENREGISTREMENT | NOM_VARIABLE[,])]; Pour rcuprer lensemble des enregistrements, Il faut donc prvoir une boucle.

4. Statut dun curseur


Pour chaque excution dun ordre de manipulation du curseur, le noyau renvoie une information appele statut, qui indique si lordre a t excut avec succs ou non. Cette information est disponible dans le programme par lintermdiaire de quatre attributs rattachs chaque curseur. - %FOUND : Cest un attribut de type boolen. Le curseur explicite est VRAI si lordre FETCH ramne au moins une ligne. Le curseur implicite est VRAI si les instructions INSERT, UPDATE et DELETE traitent au moins une ligne. - %NOTFOUND : Cest un attribut de type boolen. Le curseur explicite est VRAI si lordre FETCH ne ramne pas de lignes. Le curseur implicite est VRAI si les instructions INSERT, UPDATE et DELETE ne traitent aucune ligne. - %ISOPEN : Cest un attrib ut de type boolen ; il est VRAI si le curseur est ouvert. Le curseur implicite est toujours FAUX car Oracle referme toujours les curseurs quil ouvre aprs chaque utilisation. - %ROWCOUNT : Cet attribut est de type numrique. Le curseur implicite indique le nombre de lignes traites par les ordres INSERT, UPDATE et DELETE. Le curseur explicite est incrment chaque ordre FETCH ; il traduit donc la nime ligne traite. La syntaxe de consultation dun attribut est : NOM_CURSEUR%ATTRIBUT. SQL> declare 2 CURSOR c_produit ( v_no_Fournisseur Produit.no_Fournisseur%TYPE:=1, 3 v_code_catgorie Produit.code_catgorie%TYPE)

4 IS SELECT nomproduit,prix_unitaire FROM produit 5 6 WHERE no_Fournisseur = v_no_Fournisseur AND code_catgorie = v_code_catgorie;

7 v_produit c_produit%ROWTYPE; 8 begin 9 10 11 12 13 14 open c_produit(v_code_catgorie => 1); if c_produit%ISOPEN then dbms_output.put_line('La valeur ROWCOUNT :'|| c_produit%ROWCOUNT); loop fetch c_produit into v_produit; exit when c_produit%NOTFOUND; 4

15 16 17 18 19

dbms_output.put_line('Le produit : '''|| v_produit.nomproduit|| ''' est au prix '||v_produit.PRIX_UNITAIRE); dbms_output.put_line('La valeur ROWCOUNT : '|| c_produit%ROWCOUNT); end loop; end if;

20 close c_produit; 21 end; 22 / La valeur ROWCOUNT : 0 Le produit : 'Chai' est au prix 90 La valeur ROWCOUNT : 1 Le produit : 'Chang' est au prix 95 La valeur ROWCOUNT : 2 Dans le cas dun curseur implicite, un attribut est associ un curseur par la notation SQL%ATTRIBUT. La valeur de lattribut est relative au dernier ordre SQL excut avant son utilisation. SQL> begin 2 3 4 5 6 Update employs SET commission = 500 Where numemploy = 10; if SQL%FOUND then dbms_output.put_line('La valeur ROWCOUNT :'|| SQL%ROWCOUNT); end if;

7 end; 8 / La valeur ROWCOUNT :1

5. Les boucles et les curseurs


Dans la mesure o lutilisation principale dun curseur est le parcours dun ensemble de lignes ramens par lexcution SELECT associ, il peut tre intressant dutiliser une syntaxe plus simple pour louverture du curseur et le parcours de la boucle. Oracle propose une variante de la boucle FOR qui dclare implicitement la variable de parcours, ouvre le curseur, ralise les FETCH successifs et ferme le curseur : FOR NOM_ENREGISTREMENT IN NOM_CURSEUR LOOP INSTRUCTIONS END LOOP SQL> declare 2 3 CURSOR c_produit ( v_no_Fournisseur Produit.no_Fournisseur%TYPE:=1, v_code_catgorie Produit.code_catgorie%TYPE) 5

4 5 6

IS SELECT nomproduit,prix_unitaire FROM produit WHERE no_Fournisseur = v_no_Fournisseur AND code_catgorie = v_code_catgorie;

7 begin 8 9 10 11 end loop; for v_produit in c_produit(v_code_catgorie => 1) loop dbms_output.put_line('Le produit : '''|| v_produit.nomproduit|| ''' est au prix '||v_produit.PRIX_UNITAIRE);

12 end; 13 / Le produit : 'Chai' est au prix 90 Le produit : 'Chang' est au prix 95 Remarquez dans cet exemple que la variable v_produit est dfinie automatiquement comme une variable de type enregistrement en lecture seule. Il est galement possible de ne pas dclarer le curseur dans la section DECLARE, mais de spcifier celui-ci directement dans linstruction FOR. SQL> begin 2 3 4 5 6 7 end loop; for v_produit in (SELECT nomproduit,prix_unitaire FROM produit WHERE no_Fournisseur = 1 AND code_catgorie = 1) loop dbms_output.put_line('Le produit : '''|| v_produit.nomproduit|| ''' est au prix '||v_produit.PRIX_UNITAIRE);

8 end; 9 / Le produit : 'Chai' est au prix 90 Le produit : 'Chang' est au prix 95 PL/SQL permet aussi, pour la constitution de la requte, dutiliser les variables dclares dans le bloc ou toute autre variable accessible. SQL> declare 2 3 4 5 6 7 v_no_Fournisseur Produit.no_Fournisseur%TYPE; v_code_catgorie Produit.code_catgorie%TYPE; CURSOR c_produit IS SELECT nomproduit,prix_unitaire FROM produit WHERE no_Fournisseur = v_no_Fournisseur AND code_catgorie = v_code_catgorie;

8 begin 6

9 10 11 12 13 14

v_no_Fournisseur := 1; v_code_catgorie := 1; for v_produit in c_produit loop dbms_output.put_line('Le produit : '''|| v_produit.nomproduit|| ''' est au prix '||v_produit.PRIX_UNITAIRE); end loop;

15 end; 16 / Le produit : 'Chai' est au prix 90 Le produit : 'Chang' est au prix 95 - Attention : Prenez garde aux noms des variables lorsque vous mlangez les variables PL/SQL et les colonnes de la base dans les requtes lintrieur dun bloc PL/SQL. Si votre variable a le mme nom que la colonne, Oracle utilise toujours la colonne. Il ny a pas derreur la compilation, mais vous nobtenez pas le rsultat escompt. SQL> declare 2 3 4 5 numemploy employs.numemploy%TYPE:=1; CURSOR c_employ IS SELECT numemploy,nom FROM employs WHERE numemploy = numemploy;

6 begin 7 8 9 10 end loop; for v_employ in c_employ loop dbms_output.put_line('numro employ : '|| v_employ.numemploy|| ' a pour nom : '||v_employ.nom);

11 end; 12 / numro employ : 1 a pour nom : Zaafrani numro employ : 2 a pour nom : Chater numro employ : 3 a pour nom : Gharbi numro employ : 10 a pour nom : Ben Brahim

6. Les curseurs FOR UPDATE


Jusqu prsent, tous les exemples des curseurs taient en lecture seule. Aucune modification des donnes retournes na t effectue. Lorsquon lance un curseur avec un ordre SELECT sur la base pour rcuprer des enregistrements, aucun verrou nest mis sur les lignes slectionnes. Il y a toutefois des situations o lon souhaite verrouiller un ensemble de lignes avant mme de les avoir modifis par programme. Pour ce type de verrou, Oracle offre la clause FOR UPDATE dans la dclaration du curseur. 7

Lorsquon excute un ordre SELECT FOR UPDATE, les enregistrements ramens sont verrouills pendant toute la dure du travail. Personne ne peut modifier ces enregistrements avant quun ordre ROLLBACK ou COMMIT nait t excut. Lorsquun de ces ordres est excut, les verrous de lignes dont relchs. - Attention : Il est impossible dexcuter un ordre FETCH sur un cur seur FOR UPDATE aprs avoir fait COMMIT ou ROLLBACK. La position dans le curseur est perdue. La syntaxe de dclaration dun curseur en mise jour est : CURSOR NOM_CURSEUR [(NOM_ARGUMENT TYPE :=VALEUR_DEFAUT [,])] IS REQUETE FOR UPDATE [OF NOM_COLONNE [,])] [{NOWAIT | WAIT NB_SECONDES}]; - NOM_COLONNE : Une ou plusieurs colonnes sur laquelle porte la clause FOR UPDATE. - NOWAIT : Demande Oracle de verrouiller les enregistrements immdiatement. Si les enregistrements sont dj verrouills, alors louverture du curseur provoque une erreur. - WAIT : Si les enregistrements sont dj verrouills, alors le programme attend NB_secondes pour le dverrouillage, sinon louverture du curseur provoque une erreur. SQL> declare 2 CURSOR c_commande IS 3 4 SELECT * FROM commandes

5 WHERE TRUNC(DateEnvoi,'Month') = TRUNC(SYSDATE,'Month') 6 FOR UPDATE OF DATECOMMANDE, PORT;

La liste des colonnes spcifie aprs le mot cl OF de la clause FOR UPDATE nimplique pas de ne modifier que les colonnes listes. Las verrous sont poses sur des lignes compltes; la liste OF est seulement un moyen de documenter plus clairement ce quon a lintention de changer. Linstruction WHERE CURRENT OF permet daccder directement la ligne ramene par un lordre FETCH dun curseur dclar FOR UPDATE, afin de la traiter par une opration de mise jour (UPDATE ou DELETE). Pour spcifier que lon veuille traiter la ligne courante ramene par lordre FETCH, on doit ajouter la clause : WHERE CURRENT OF NOM_CURSEUR ; lopration de mise jour (UPDATE ou DELETE). SQL> declare 2 3 4 CURSOR c_employ IS SELECT nom,prnom, fonction, salaire, commission FROM employs FOR UPDATE OF SALAIRE, COMMISSION; v_employ c_employ%ROWTYPE;

5 begin 6 7 8 for v_employ in c_employ loop if v_employ.fonction = 'Chef des ventes' and v_employ.Salaire + v_employ.commission < 2000 then 8

9 10 11

Update employs SET salaire = salaire * 1.1 WHERE CURRENT OF c_employ; dbms_output.put_line('Modification de salaire de l''employ : '|| v_employ.nom|| ' '

||v_employ.prnom); 12 13 14 end if; end loop; COMMIT;

15 end; 16 / Modification de salaire de l'employ : Ben Brahim Nadra

7. Prsentation des exceptions


Le mcanisme de gestion derreurs dans PL/SQL, est appel gestionnaire des exceptions . Le traitement des exceptions PL/SQL permet au dveloppeur de planifier sa gestion et dabandonner le traitement en prsence dune erreur ou de le continuer si lerreur nest pas suffisamment importante. Comme on le sait, un bloc PL/SQL est divis de quatre parties : len-tte, la section de dclaration, la section dexcution et la section dexception. Lorsquune exception est dclenche dans la section dexcution dun bloc PL/SQL, la section dexception EXCEPTION prend le contrle. PL/SQL vrifie si, parmi les diffrents gestionnaires dexception, lun traite cette exception spcifique. La syntaxe dune section dexception est la suivante : EXCEPTION WHEN NOM_EXCEPTION [OR NOM_EXCEPTION ] THEN INSTRUCTIONS ; [WHEN OTHERS THEN INSTRUCTIONS ;] END; Une section dexception unique peut contenir plusieurs gestionnaires dexception. Les gestionnaires dexception ont une structure comparable celle de lordre conditionnel CASE.

SQL> begin 2 3 4 5 6 declare v_nom_produit Produit.nomproduit%TYPE; begin SELECT nomproduit INTO v_nom_produit FROM produit WHERE code_catgorie = 3; 9

7 8 9

dbms_output.put_line('Vous ne verrez pas cette ligne !!!'); end; dbms_output.put_line('Suite de traitements.');

10 end; 11 / Declare * ERREUR la ligne 1 : ORA-01403: Aucune donne trouve ORA-06512: ligne 5 SQL> begin 2 3 4 5 6 7 8 9 10 11 12 declare v_nom_produit Produit.nomproduit%TYPE; begin SELECT nomproduit INTO v_nom_produit FROM produit WHERE code_catgorie = 3; dbms_output.put_line('Vous ne verrez pas cette ligne !!!'); exception When NO_DATA_FOUND Then dbms_output.put_line('Aucune catgorie n''a t trouve.'); end; dbms_output.put_line('Suite de traitements.');

13 end; 14 / Aucune catgorie n'a t trouve. Suite de traitements. Dans la premire requte, il ny a pas de gestionnaire dexception. Quand lerreur survient (il ny a pas de produit de la catgorie 3), et le programme est arrt, affichant un message derreur. La deuxime requte assure le traitement dune exception NO_DATA_FOUND. Aprs le traitement de cette exception on ne revient pas dans le bloc ayant gnr lexception, on quitte compltement le bloc mais le programme continue normalement. Notez que la clause WHEN traite des exceptions nommes. Si aucun gestionnaire ne correspond lexception dclenche, les ordres associs la clause WHEN OTHERS sont excuts si elle est prsente.

8. Les exceptions prdfinies


Toutes les erreurs possdent un numro didentification unique. Mais elles ne peuvent tre interceptes dans un bloc PL/SQL que si un nom est associ au numro de lerreur Oracle. Les exceptions prdfinies sont dclares dans le package STANDARD de PL/SQL. La liste des exceptions prdfinies est : 10

ACCESS_INTO_NULL : On a tent daffecter une valeur un objet non initialis. ORA-6530 SQLCODE = -6530 CASE_NOT_FOUND : Il ny a pas de choix WHEN correspondant dans une instruction CASE et loption ELSE na pas t dfinie. ORA-6592 SQLCODE= -6592 COLECTION_IS_NULL : On a tent dutiliser des mthodes dune collection, autre que EXISTS, ou essay daffecter une valeur un lment pour une collection non initialise. ORA-6531 SQLCODE = 6531

CURSOR_ALREADY_OPEN : On a tent douvrir un curseur qui ltait dj. Il faut fermer un curseur ava nt de louvrir ou de le rouvrir. ORA-6511 SQLCODE = -6511 DUP_VAL_ON_INDEX : Un ordre INSERT ou UPDATE a tent dinsrer un doublon dans une colonne ou un groupe de colonnes soumis un index unique. ORA-6592 SQLCODE = -6592 INVALID_CURSOR : On a rfrenc un curseur invalide. Cela arrive lorsque lon FETCH ou lon ferme, un curseur avant de louvrir ORA-01001 SQLCODE = -1001 INVALID_NUMBER : PL/SQL excute un ordre qui ne parvient pas convertir une chane de caractres en nombre. ORA-01722 SQLCODE = -1722 LOGIN_DENIED : Un programme tente de se connecter Oracle avec une combinaison login/mot de passe invalide. ORA-01017 SQLCODE= -1017 NO_DATA_FOUND : Cette exception est dclenche dans 3 cas. o Lorsquon excute un ordre SELECT INTO qui ne ramne aucun enregistrement. o Lorsquon rfrence une ligne non initialise dune table PL/SQL o Lorsquon tente de lire aprs la fin dun fichier avec la package UTL_FILE. ORA-01403 SQLCODE= +100

NOT_LOGGED_ON : Un programme a tent dexcuter un appel la base, en gnral un ordre LMD, avant dtre connect. ORA-01012 SQLCODE= -1012 PROGRAM_ERROR : Erreur interne de PL/SQL. ORA-06501 SQLCODE=-1012 RAWTYPE_MISMATCH : On a tent daffecter une variable enregistrement incompatible avec lenregistrement retourn par la commande FETCH. ORA-06504 SQLCODE = -6504 STORAGE_ERROR : Le programme a puis la mmoire disponible, ou la mmoire est corrompue. ORA-06500 SQLCODE = -6500 TIMEOUT_ON_RESOURCE : Le dlai maximum dattente dune ressource par Oracle a expir. ORA-00051 SQLCODE = -51 TOO_MANY_ROWS : Un ordre SELECT INTO a ramen plus dune ligne. ORA-01422 SQLCODE=-1422 VALUE_ERROR : Lorsque PL/SQL rencontre, en dehors dun ordre LMD, une erreur de conversion, de troncature ou de bornes sur des donnes numriques ou alphanumriques. ORA-06502 SQLCODE = -6502 11

ZERO_DIVIDE : Un programme a tent une division par zro. ORA-01476 SQLCODE = -1476

9. Les exceptions anonymes


Pour les exceptions anonymes (nayant pas des noms prdfinis), on utilisera la clause WHEN OTHERS pour les traiter. Il est toutefois souhaitable de pouvoir dterminer au sein du gestionnaire dexceptions la nature de lerreur survenue. Oracle fournit les fonctions SQLCODE et SQLERRM, qui renvoient respectivement le code et le message derreur correspondant lexception. SQL> begin 2 DELETE FROM employs Where NumEmploy = 1;

3 exception 4 5 6 When OTHERS Then dbms_output.put_line('SQLCODE =' || SQLCODE); dbms_output.put_line('SQLERRM =' || SQLERRM);

7 end; 8 / SQLCODE =-2292 SQLERRM =ORA-02292: violation de contrainte (ZAAFRANI.COMMANDES_NUMEMPLOY_FK) d'intgrit - enregistrement fils existant On prfrera, dans de nombreux cas, traiter ces erreurs de manire spcifique afin de mieux les documenter. Pour ce faire, on affecte un nom particulier lerreur que le programme est susceptible de rencontrer, puis on crit un gestionnaire dexceptions ddi cette exception nomme. Pour associer un nom un code derreur interne, on se servira dune pragma, une instruction spciale du compilateur, qui est traite lors de la compilation plutt que durant lexcution. Linstruction PRAGMA EXCEPTION_INIT demande au compilateur dassocier une exception utilisateur un code derreur Oracle spcifique. Une fois lerreur associe un nom, i l est possible de la dclencher volont et dcrire un gestionnaire dexceptions qui la traitera. Linstruction PRAGMA EXCEPTION_INIT doit apparatre dans la section de dclaration dun bloc, aprs la dclaration du nom dexception qui est utilis dans linstruction. La syntaxe de dclaration dune exception anonyme : DECLARE NOM_EXCEPTION EXCEPTION; PRAGMA EXCEPTION_INIT(NOM_EXCEPTION, CODE_ERREUR); BEGIN EXCEPTION WHEN NOM_EXCEPTION THEN 12

INSTRUCTIONS; END; CODE_ERREUR : Cest le code derreur Oracle, y compris le signe moins si le code derreur est ngatif, ce qui est en gnral le cas. SQL> Declare 2 3 4 DELETE_CASCADE_ENFANT EXCEPTION; PRAGMA EXCEPTION_INIT(DELETE_CASCADE_ENFANT, -2292); v_NumEmploy employs.NumEmploy%TYPE;

5 begin 6 v_NumEmploy := &Numro_Employ;

7 DELETE FROM employs Where NumEmploy = v_NumEmploy; 8 exception 9 10 11 12 13 14 When DELETE_CASCADE_ENFANT Then dbms_output.put_line('exception : DELETE_CASCADE_ENFANT'); DELETE FROM commandes Where NumEmploy = v_NumEmploy; UPDATE employs SET RendCompte = NULL Where RendCompte = v_NumEmploy; DELETE FROM employs Where NumEmploy = v_NumEmploy; ROLLBACK;

15 end; 16 / Entrez une valeur pour numro_employ : 1 exception : DELETE_CASCADE_ENFANT Lexemple prcdent montre la dclaration dune exception associe lerreur ORA-2292. Cette erreur survient lorsque lon tente deffacer un enregistrement qui est rfrenc comme cl trangre. Dans le gestionnaire dexceptions, tous les enregistrements correspondants dans la table commandes sont effacs et les valeurs du champ rend compte des enregistrements correspondants sont mises NULL.

10. Les exceptions utilisateur


Les exceptions prdfinies par PL/SQL se rapportent aux erreurs internes ou systme. Les problmes rencontrs par un utilisateur dans une application sont pour la plupart spcifiques cette application. Un programme peut ncessiter la gestion derreurs telle que solde ngatif dans un compte . Ces erreurs constituent des exceptions aux traitements normaux , et vos programmes doivent les grer. Ces exceptions sont gres de la mme manire que les exceptions internes, comme dans la syntaxe suivante : DECLARE NOM_EXCEPTION EXCEPTION; BEGIN 13

RAISE NOM_EXCEPTION; EXCEPTION WHEN NOM_EXCEPTION THEN INSTRUCTIONS; END; RAISE : permet de lancer une exception utilisateur. SQL> Declare 2 3 4 UPDATE_EMPLOYES EXCEPTION; v_NumEmploy employs.NumEmploy%TYPE; v_salaire employs.salaire%TYPE;

5 begin 6 7 8 9 10 11 12 13 14 15 16 v_NumEmploy := &Numro_Employ; v_salaire := &salaire; for emp in ( SELECT salaire From employs WHERE NumEmploy = v_NumEmploy) loop if v_salaire < emp.salaire then dbms_output.put_line('Le salaire actuel est '|| emp.salaire) RAISE UPDATE_EMPLOYES; end if; end loop; UPDATE employs SET salaire = v_salaire WHERE NumEmploy = v_NumEmploy;

17 exception 18 19 20 end; 21 / Entrez une valeur pour numro_employ : 10 Entrez une valeur pour salaire : 1200 Le salaire actuel est 1210 Exception utilisateur : UPDATE_EMPLOYES Le bloc PL/SQL commence par la dfinition dune exception UPDATE_EMPLOYES. Si le salaire saisi est infrieur au salaire actuel, la modification de lemploy nest pas effectue et lexception est lance. When UPDATE_EMPLOYES Then dbms_output.put_line('Exception utilisateur : UPDATE_EMPLOYES');

14

Você também pode gostar