Upload
godefrey-rossignol
View
106
Download
3
Embed Size (px)
Citation preview
Le Langage PL/SQL
IUPm3- Université de Nantes
Plan du Cours
• Introduction au langage PL/SQL
• Les variables
• Traitements Conditionnels
• Traitements répétitifs
• Les curseurs
• Gestion d’exceptions
Comparaison avec SQL• SQL
– Langage assertionnel et non procédural
• PL/SQL– Langage procédural, qui intègre des ordres SQL
• SELECT, INSERT, UPDATE, DELETE• INSERT, UPDATE, DELETE• Gestion de transactions: COMMIT, ROLLBACK, SAVEPOINT
• Langage à part entière comprenant– Définition de variables, constantes, expressions, affectations– Traitements conditionnels, répétitifs – Traitement de Curseurs – Traitement des erreurs et d’exceptions – Etc…
Exemple
DECAREqty_on_hand NUMBER(5);
BEGINSELECT quantity INTO qty_on_hand FROM inventoryWHERE product = ‘TENNIS RACKET’FOR UPDATE of quantity;IF qty_on_hand > 0 THEN
UPDATE inventory SET quantity quantity – 1WHERE product = ‘TENNIS RACKET’;INSERT INTO purchase_record
VALUES(‘Tennis racket puchased’,SYSDATE);ENF IF;
COMMIT;END;
Structure
[DECLARE--declarations de variables contantes
-- exceptions et curseurs]BEGIN [nom-bloc]
--instructions SQL et extentions
[EXCEPTIONS -- Traitement des exceptions]
END; ou END nombloc
Architecture
PL/SQL Engine
PL/SQLBlock
PL/SQLBlock
ProceduralStatement Executor
Procedural
SQL
SQL Statement Executor
Types de Variables
• Variables locales:– De type simple: type de base ou booléen– Faisant référence à la métabase– De type composé: Tableau, Record
• Variables Extérieures:– Variables d’un langage hote (ex: C) (préfixés par :)– Paramètres (ex: SQL interactif par &)– Champs d’écrans (Forms)
Variables de type Simple
Declarenom char(15);salaire number(7,2);embauche DATE ;réponse boolean;
Variables sur la métabase• Reprend
– Soit le même type qu’une colonne dans une table– Soit la même structure qu’une ligne dans une table– Soit le même type qu’une variable précédemment définie
• Syntaxe nom_var1 table.colonne%TYPE
nom_var2 table%ROWTYPE nom_vars3 nom_var1%TYPE• Exemples:
nom emp.ename%TYPE;enreg emp%ROWTYPE;commi number(7,2);Salaire commi%TYPE;
Initialisation et visibilité• Dans la déclaration
Nom char(10) := ‘Miller’; Reponse boolean := TRUE;
• Constantes Pi CONSTANT number (7,2) := 3.14;
• Interdire les valeurs non renseignées: NOT NULL Debut number NOT NULL := 10;
• L’ordre SELECTSelect col1, col2Into var1, var2From table[Where condition ];
• Règle– La clause INTO est obligatoire– Le select ne doit ramener qu’une ligne
• Visibilité: bloc de déclaration + blocs imbriqués
Exemple
Declarenom_emp char(15);salaire emp.sal%TYPEcommission emp.comm%TYPE;nom_départ char(15);
BeginSelect ename, sal, comm, dnameInto nom_emp, salaire, commission, nom_départFrom emp, deptWhere ename = ‘MILLER’ and emp.deptno = dept.deptno…
End;
Traitements Conditionnels
IF condition THENinstruction; … instruction;
[ELSEIF condition THENinstruction; … instruction; ]
…[ELSEIF condition THEN
instruction; … instruction;][ELSE
instruction; … instruction;]END-IF;
Une instruction IF peut contenir plusieurs clauses ELSEIF, mais une seule clause ELSE.
IF THEN ELSE
• IF THENIF condition Then traitement ENDIF;
• Exemple: IF sales > quota THEN
compute_bonnus(emp_id);
UPDATE payroll SET pay = pay + bonus where empno = emp_id;
END IF;
• IF THEN ELSE
IF condition THEN
traitement1
ELSEtraitement2;
END IF;
• Exemple:IF trans_type = ‘CR’ THEN
UPDATE accounts SET balance = balance + credit WHERE …
ELSE
UPDATE accounts SET balance = balance – debit WHERE …
END IF;
• IF condition1THENTraitement 1;
ELSEIF condition2 THEN Traitement2; ELSE
traitement3; END IF;• Exemple:
IF sales > 50000 THENbonus := 1500;
ELSEIF sales > 35000 THENbonus := 500;
ELSE bonus := 100;
IF THEN ELSEIF
IF condition1 THEN
traitement1;
ELSE
IF condition2 THEN
traitement2;
ELSE
IF condition3 THEN
traitement3;
END IF;
END IF;
END IF;
IF condition1 THEN
traitement1;
ELSEIF condition2 THEN
traitement2;
ELSEIF condition3 THEN
END IF;
Sont équivalents
ExempleDECLARE
emploi char (10);nom char(15) := ‘MILLER’;ctl char(30);
BEGINSelect job INTO emploi FROM emp WHERE ename = nom;IF emploi is null THEN ctl := nom || ‘n’apas d’emploi ’;ELSEIF emploi = ‘SALESMAN’
THEN update emp set comm = 1000 where ename = nom; ctl := nom || ‘commission modifiee’;
ELSE update emp
set comm = 0 where ename = nom; ctl := nom || ‘pas de commission’;
END IF; insert into resultat values(ctl);
commit; END;/
OBS: || fait la concaténation et / provoque la soumission du bloc au moteur PL/SQL
Répétition Instruction LOOP simpleLOOP
instruction; … instruction;END LOOP;
Instruction While … LOOPWHILE condition LOOP
instruction; … instruction;
END LOOP;
Instruction FOR.. LOOPFOR variable_boucle IN [REVERSE] borne_inférieure … borne_supérieure LOOP
instruction; … instruction;END LOOP;
FOR i in 1.. Max_loop LOOPdbms_output.put_line(‘i: ‘|| to_char(i));
END LOOP;
EXIT, GOTO, NULL, Commentaires
Instruction GOTOGOTO nom_étiquette;
Instruction NULLIF (mod(i,10) = 0) THEN
i := i + 1;else
NULL;END IF;
Commentairesinstruction;
-- Bla bla blainstruction
Ou avec /* Bla bla bla */
EXAMPLE 1
DECLAREmax_records CONSTANT int := 100;i int := 1;BEGINFOR i in 1.. Max_records LOOP
if (mod(i,10) = 0) thenINSERT INTO teste_table (val, current_date) values (i, SYSDATE);
elseNULL;
END IF;END LOOP;COMMIT;END;/
Exemple 2SQL> set serveroutput onSQL >SQL> declare 2 2 Average_Body_Temp Patient.Body_Temp_Deg_F%type; 3 3 begin 4 4 dbms_output.enable; 5 5 select avg(Body_Temp_Deg_F) into Average_Body_Temp from Patient; 6 6 dbms_output.put_line(‘Température moyenne du corps en degrés F: ‘ || to_char(Average_Body_Temp,’999.99’)); 7 7 end; 8 / Temperature moyenne du corps en degrés F: 99,80 Procedure PL/SQL terminée avec succès.
Imbrication de blocs
PL/SQL permet d’inclure des sous-blocs dans un bloc (pratique n’est pas recommandé).Declare
x real;Begin
…declare
x real;begin
…end;…
End;
x extérieur
x extérieur
x intérieur Visibilité
Procédures
PROCEDURE nom_procédure [(argument1 … [, argumentN) ] IS[déclarations_de_variables_locales ]BEGIN
section_exécutable[section_exception]
END [nom_procedure]
• Si on fait: CREATE PROCEDURE ou FUNCTION…, la procédure ou fonction qui est crée est permanente. Elle peut être appelée par un script SQL*Plus, un sous-programme PL/SQL etc.
• Les variables déclarées dans une procédure ne sont pas accessibles en dehors d’elle-même.
Exemple
DeclareNew_patient_ID Patient.Patient_ID %type;High_Fever constant real := 42.0;
Procedure Record _Patient_Temp_Deg_C(Patient_ID varchar2, Body_Temp_Deg_C real) isTemp_Deg_F real;Begin
Temp_Deg_F := (9.0/5.0)*Body_Temp_Deg_C + 32.0;insert into Patient (Patient_ID, Body_Temp_Deg_F) values (Patient_ID, Temp_Deg_F); Temp_Deg_F)commit;
end;
BeginNew_Patient_ID := ‘GG9999’;Record_Patient_Temp_Deg_C (Nex_Patient_ID, High_Fever);
End;/
Fonctions
FUNCTION nom_fonction [argument1… [, argumentN) ]RETURN type_données-fonction IS[déclaration-variabels_locales]BEGINSection_exécutable[section_exeption]END [nom_fonction];
ExempleDeclareCourse_ID Course.Course_ID%type;
Function Max_Additional_Fees (Dept_ID IN varchar2)return varchar2 is
Additional_Fees Course.Additional_Fees%type;Units Cours.Units%type;Cours_ID Course.Course_ID%type;Begin
select Course_ID into Cours-IDfrom Coursewhere Departement_ID = Dept_ID and additional_Fees in
(select max(Additional_Fees) from Course where Departement_ID = Dept_ID);
return Course_ID;End;Begin
dbms_output.enable;Course_ID := Max_Additional_Fees(‘ECON’);dbms_output.put_line(‘Course_ID: ‘|| Course_ID);
End;/
Recherche de données avec un curseur
• Definition– Un curseur est un mécanisme permettant de rechercher un nombre
arbitraire de lignes avec une instruction SELECT.
• Deux types de curseurs:– Le curseurs implicite: généré et géré par le noyau pour chaque
ordre SQL d’un bloc
– Le curseur explicite: généré para l’utilisateur pour traiter un ordre SELECT qui ramène plusieurs lignes. Utilisation:
– Déclaration
– Ouverture du curseur
– Traitement des lignes
– Fermeture du curseur
Déclaration d’un curseur explicite
• Se fait dans la section Declare
• Syntaxecursor nom_curseur is ordre_select
• Exemple
Declare
cursor dept_10 is
select ename, sal From emp
where deptno = 10 order by sal;
Begin
…
End;
Ouverture• L’ouverture déclanche:
– Allocation de mémoire pour le lignes du curseur
– L’analyse syntaxique et sémantique du select
– Le positionnement de verrous éventuels
• L’ouverture se fait dans la section Begin
• Syntaxe: OPEN nom_curseur;
Declare cursor dept_10 is
select ename, sal From empwhere deptno = 10 order by sal;
Begin…;open dept_10;
…; End;
Traitement de Lignes
• Les lignes ramenées sont traitées une par une, la valeur de chaque colonne doit être stockée dans une variable réceptrice
• Syntaxe:Fetch nom_curseur into liste_variables;
• Le Fetch ramène une ligne à la fois.
ExempleDeclare
cursor dept_10 isselect ename, sal From empwhere deptno = 10 order by sal;
nom emp.ename%TYPE;salaire emp.sal%TYPE;
BeginOpen dept_10;Loop
Fetch dept_10 into nom, salaire;If salaire > 2500then insert into résultat values (nom,salaire);end if;exit when salaire = 5000;
end loop;…
End;
Fermeture• Syntaxe: Close nom_curseur;
• Action: libère la place de mémoire
Declare cursor dept_10 is
select ename, sal From empwhere deptno = 10 order by sal;
nom emp.ename%TYPE;salaire emp.sal%TYPE;
BeginOpen dept_10;Loop
Fetch dept_10 into nom, salaire;If salaire > 2500then insert into résultat values (nom,salaire);end if;exit when salaire = 5000;
end loop;close dept_10;
End;
ExemplePrompt Nombre de salaires ?Accept nombre;Declare
Cursor c1 is select ename, sal from emp order bay sal desc;
vename emp.ename%TYPE;vsal emp.sal%TYPE;
Beginopen c1;for i in 1..&nombreloop
fetch c1 into vename, vsal;insert into résultat values (vsal, vename);
end loop;close c1
End;
Les attributs d’un curseur
• Définition indicateurs sur l’état d’un curseur.– %FOUND : nom_curseur%FOUND
• TRUE: le dernier FETCH a ramené une ligne
• FALSE: plus de ligne
– %NOTFOUND: nom_curseur%NOTFOUND• TRUE: le dénier FETCH n’a pas ramené de ligne
– %ISOPEN: nom_curseur%ISOPEN• TRUE: le curseur est ouvert
– %ROWCOUNT: nom_curseur%rowcount• Nbre de lignes ramenées par le FetCH
Exemple - %FOUND
Declare cursor dept_10 is
select ename, sal From empwhere deptno = 10 order by sal;
nom emp.ename%TYPE;salaire emp.sal%TYPE;
BeginOpen dept_10;Fetch dept_10 into nom, salaire;While dept_10%FOUNDLoop
If salaire > 2500then insert into résultat values (nom,salaire);end if;Fetch dept_10 into nom, salaire;
end loop;close dept_10;
End;
Exemple - %NOTFOUND
Declare cursor dept_10 is
select ename, sal From empwhere deptno = 10 order by sal;
nom emp.ename%TYPE;salaire emp.sal%TYPE;
BeginOpen dept_10;Loop
Fetch dept_10 into nom, salaire;Exit when dept_10%NOTFOUND;If salaire > 2500then insert into résultat values (nom,salaire);end if;
end loop;close dept_10;
End;
Exemple - %ISOPEN
Declare cursor dept_10 is
select ename, sal From empwhere deptno = 10 order by sal;
nom emp.ename%TYPE;salaire emp.sal%TYPE;
BeginIf not(dept_10%ISOPEN) the Open dept_10; end if;Loop
Fetch dept_10 into nom, salaire;Exit when dept_10%NOTFOUND;If salaire > 2500then insert into résultat values (nom,salaire);end if;
end loop;close dept_10;
End;
Exemple - %ROWCOUNT
Declare cursor dept_10 is
select ename, sal From empwhere deptno = 10 order by sal;
nom emp.ename%TYPE;salaire emp.sal%TYPE;
BeginOpen dept_10; Loop
Fetch dept_10 into nom, salaire;Exit when dept_10%NOTFOUND or dept_10%ROWCOUNT > 15;If salaire > 2500then insert into résultat values (nom,salaire);end if;
end loop;close dept_10;
End;
Gestion des Erreurs
• Section Exception
• Anomalie programmeur
• Erreur Oracle
Section Exception
• Notion d’exception: traitements d’erreurs
• Types d’erreurs:
– Erreurs internes Oracle (Sqlcode <> 0)
– Erreurs programme utilisateur
• Règles à respecter
– Définir et donner un nom à chaque erreur
– Associer ce nom à la section Exception (partie declare)
– Définir la traitement dans la partie Exception
Gestion des Exceptions
• SyntaxeEXCEPTION
WHEN nom_exception1 THENinstructions_PL_SQL;
…WHEN nom_exceptionN Then
instructions PL/SQL;…[WHEN OTHERS THEN
instrctions_PL/SQL;]END;
• Sortie du bloc après exécution du traitement
Exceptions Prédéfinies
• DUP_VAL_ON_INDEX– Lorsqu’une instruction SQL tente de créer une valeur dupliquée dans une
colonne sur laquelle un index unique a été défini
• INVALID_NUMBER– Lorsqu’une instruction SQL spécifie un nombre invalide
• NO_DATA_FOUND– Lorsqu’une instruction Select ne retourne aucune ligne
• TOO_MANY_ROWS– Une instruction Select ne peut pas renvoyer plus d’une ligne sans
provoquer l’exception TOO_MANY_ROWS
• VALUE_ERROR– Provoquée dans des situations d’erreur résultant de valeurs tronquées ou
converties
ExempleDeclare Course_Rec Cours%ROWTYPE;Begin
dbms_output.enable;select *into Course_Recfrom Coursewhere Course_ID = ‘777’;
Exceptionwhen No_Data_Found then
dbms_output.put_line(‘Aucune donnée retournée’);when other then null;
End;/Aucune donnée retournéeProcedure PL/SQL terminé avec succès.
Déclaration d’une ExceptionDeclare
pas_comm EXCEPTION;salaire emp.sal%TYPE;commi emp.comm%TYPE;numero emp.empno%TYPE;
BeginSelect sal, comm, empno into salaire, commi, numerofrom emp where empno := :num_emp;If commi = 0 or commi is nullthen raise pas_commelse traitement …end if;
Exception When pas_commthen insert into resultat values(numéro, salaire, ‘pas de comm’);
End;
Obs: num_emp fait référence à une variable extérieure au bloc PL/SQL)
Test d’exécution avec SQLCODE et SQLERRM
• SQLCODE– Fonction prédéfinie qui renvoie le statut d’erreur système de l’instruction
qui vient d’être exécutée (si sans erreur, SQLCODE = 0).
• SQLERRM– Fonction prédéfinie qui renvoie le message d’erreur associé à la valeur
retournée par SQLCODE (si sans erreur, SQLERRM = ‘ORA-0000’).
DeclareBegin
dbms_output.enable;dbms_output.put_line(‘SQLCODE: ‘ || to_char(SQLCODE));dbms_output.put_line(‘SQLERRM: ‘ || SQLERRM);
End;/SQLCODE: 0SQLERRM: ORA-0000: exécution normale, terminé avec succès
ExempleDeclareClass_Rec Class%ROWTYPE;Begin
dbms_output.enable;select * into Class_Recfrom class
Exceptionwhen OTHERS then
dbms_output.put_line(‘SQLCODE: ‘ || to_char(SQLCODE));dbms_output.put_line(SQLERRM);
End;/SQLCODE: -1422ORA-01422: l’extraction exacte ramène plus que le nombre de lignes demandéProcédure PL/SQL terminée avec succès.