Vous êtes sur la page 1sur 142

CHAPITRE 4 PL/SQL

 Langage SQL en mode procédural (PL/SQL):

1) Introduction et Blocs PL/SQL


2) PL/SQL Déclaration des variables , boucle, alternatives, affichage , GOTO
3) La gestion des exceptions
4) Curseurs
5) Procédures et fonctions stockées
6) Sous-blocs PL/SQL
7) Les Déclencheurs (Triggers)
8) Groupement de procédures et packages
Langage PL/SQL
Pourquoi PL/SQL ?
PL/SQL = PROCEDURAL LANGUAGE/SQL

 SQL est un langage non procédural

 Les traitements complexes sont parfois difficiles à écrire si on ne peut


utiliser des variables et les structures de programmation comme les
boucles et les alternatives

 On ressent vite le besoin d’un langage procédural pour lier plusieurs


requêtes SQL avec des variables et dans les structures de
programmation habituelles

Langage PL/SQL

Principales caractéristiques

 Extension de SQL : des requêtes SQL cohabitent avec les structures de


contrôle habituelles de la programmation structurée (blocs, alternatives,
boucles).

 La syntaxe ressemble au langage Pascal.

 Un programme est constitué de procédures et de fonctions.

 Des variables permettent l’échange d’information entre les requêtes SQL


et le reste du programme


Langage PL/SQL

Utilisation de PL/SQL
 PL/SQL peut être utilise pour l’écriture des procédures stockées et des
triggers.

(Oracle accepte aussi le langage Java)

 PL/SQL convient aussi pour écrire des fonctions utilisateurs qui peuvent être
utilisées dans les requêtes SQL (en plus des fonctions prédéfinies).


Langage PL/SQL

Utilisation de PL/SQL (suite)

 Le PL/SQL peut être utilisé sous 3 formes :

1
un bloc de code, exécuté comme une unique commande SQL, via un
interpréteur standard (SQLplus ou iSQL*PLus)
2

3 un fichier de commande PL/SQL

un programme stocké (procédure, fonction, trigger)


Langage PL/SQL

Blocs

Un programme est structuré en blocs d’instructions de 3 types :

procédures ou bloc anonymes, SQL> start script.sql ou SQL>@ script.sql


procédures nommées,

fonctions nommées.

Un bloc peut contenir d’autres blocs.

Considérons d’abord les blocs anonymes.


Langage PL/SQL

Structure d’un bloc anonyme

DECLARE
−- d e f i n i t i o n d e s v a r i a b l
Seuls BEGIN et END
es
sont
BEGIN
−− c o d e du
obligatoires
programme
Les blocs se terminent par un ;
EXCEPTION
−− c o d e de g e s t i o n d es
erreurs
END ;

Faisons ensemble un exemple sur SQL developer


Langage PL/SQL

Commentaires
-- Pour une fin de ligne

/* Pour
plusieurs
lignes */
Langage PL/SQL

Affichage : PROMPT , dbms_output.put_line


Lecture : ACCEPT en précédant par & la variable à lire
pour paramétrer la variable

Exemple : voir l’exemple de slide suivant


Langage PL/SQL
Exemple de base d’un bloc PL/SQL
set serveroutput on;
declare
r number;
n1 number;
n2 number;
Begin
n1:=6;
n2 := 12;
r:=n2/n1;
dbms_output.put_line('rrr est egale à : '||r);
exception
when zero_divide then
dbms_output.put_line('ERROR §§§');
end ;
/
Langage PL/SQL

Déclaration, initialisation des variables

 Identificateurs Oracle :
30 caractères au plus,

commence par une lettre,

peut contenir lettres, chiffres,_ $ et # pas sensible à la casse.

 Portée habituelle des langages à blocs

 Doivent être déclarées avant d’être utilisées


Langage PL/SQL

Déclaration et initialisation
Syntaxe : Nom_variable type_variable := valeur;
Initialisation
Nom_variable := valeur;

Déclarations multiples interdites.


Exemples

age integer;
nom varchar(30);
dateNaissance date;
 ok boolean := true;


Langage PL/SQL

Plusieurs façons d’affecter une valeur à une variable


Opérateur d’affectation n:=

Directive INTO de la requête SELECT.

Exemples
dateNaissance := to_date(’10/10/2004’,’DD/MM/YYYY’);

SELECT nom INTO v_nom FROM employees WHERE id_employees = 509;

V_sal:= 4000

Select departement_id into det_id from employees V_sal:= 4000

Attention

Pour eviler les conflits de nommage, préfixer les variables PL/SQL par v_
Langage PL/SQL

SELECT ...INTO ...

Instruction :
SELECT expr1,expr2, ...INTO var1, var2, ...

Met des valeurs de la BD dans une ou plusieurs variables var1, var2, ...

Le SELECT ne doit retourner qu’une seule ligne

Avec Oracle il n’est pas possible d’inclure un SELECT sans INTO dans un programme
PL/SQL.
Pour retourner plusieurs lignes, voir la suite du cours sur les curseurs.


Langage PL/SQL
Types de variables
VARCHAR2
Longueur maximale : 32767 octets ;
Exemples :
name VARCHAR2(30);
name VARCHAR2(30) := ’toto’ ;

NUMBER(long,dec)
Long : longueur maximale ;
Dec : longueur de la partie décimale ;
Exemples.

Num_tel number(10);

Salaire number(5,2):=142.12 ;


Langage PL/SQL
Types de variables (suite)
DATE
Fonction TO DATE ;
Exemples :
Start_date := to_date(’29-SEP-2003’,’DD-MON-YYYY’);

La vraible sttart date est evaluée et analysée par oracle par 2 chiffre pour le jour, trois
letters pour le mois et l’année sur 4 chirffrer separées par un tiret (-)

start_date := to _date(’29-SEP-2003:13:01’,’DD-MON-YYYY:HH24:MI’) ;
Ici La vraible start_date est evaluée et analysée par oracle par 2 chiffre pour le jour,
trois letters pour le mois et l’année sur 4 chirffrer separées par un tiret (-). Avec aussi
l’heurs et les minutes

BOOLEAN
TRUE
FALSE
NULL


Langage PL/SQL
Déclaration %TYPE et %ROWTYPE

V_nom emp.nom.%TYPE;

On peut déclarer qu’une variable est du même type qu’une


colonne
d’une table (ou de meme type qu’ autre variable).
V_employe emp%ROWTYPE;

Une variable peut contenir toutes les colonnes d’un tuple d’une
table
(la variable v_employe contiendra une ligne de la table emp).
Important pour la robustesse du code


Langage PL/SQL
Déclaration %TYPE et %ROWTYPE
-Exemple
DECLARE
v_employe EMPLOYEES%ROWTYPE;
v_nom EMPLOYEES.FIRST_NAME%TYPE;
BEGIN
SELECT * INTO v_employe FROM EMPLOYEES
WHERE employee_id=100 ;
v_nom :=v_employe.FIRST_NAME;
v_employe.department_id:=20; Vérifier à bien retourner un seul tuple
v_employe.employee_id:=7777; avec la reqête SELECT ...INTO ...
v_employe.EMAIL:='changyah';
INSERT into employees VALUES v_employe;
dbms_output.put_line ('ttt '|| v_employe.employee_id);
END;

Exercice :
a- Créer un bloc PL/SQL pour insérer un nouveau département dans la table
DEPARTEMENTS (DEPT_ID, DEPT_NAME, LOCATION_ID)
- Utiliser la séquence DEPT_ID_SEQ pour générer un numéro de département
(DEPT_ID).
- Créer un paramètre pour lire le nom du département du clavier.
- Laisser le numéro de LOCATION_ID à NULL.
- Afficher le numéro de département qu »on vient d’inseré
b- enregistrer le code dans le fichier scipt1.sql , donner la commande de
exécution de scipt1.sql .
Solution
set serveroutput ON
ACCEPT p_dept_nom PROMPT ‘Entrer un nom de département : ‘
Declare
Numd number;
BEGIN
INSERT INTO departments VALUES (dept_id_seq.NEXTVAL, '&p_dept_nom', NULL,null);
COMMIT;
Select dept_id_seq.CURRVAL into Numd from dual;
dbms_output.put_line ('num depart inseré est '|| Numd);
END;
/
Execution ( le code est enregistré dans le fichier script1.sql
SQL> start script1.sql
Ou
SQL> @ script1.sql
Exercice 2
Créer un bloc PL/SQL pour supprimer le département créé
précédemment en
-Créant r un paramètre pour le numéro de département à
supprimer ,
-A ffichant le nombre de département avant et après la suppression
Langage PL/SQL : Commandes

Les alternatives (if , else, elesif, case )

Les boucles (loop, while , for )

La commande GOTO

Affichage dbms_output.put_line ()
et retour chariot chr(10)
Langage PL/SQL : Commandes
Test conditionnel
IF-THEN

IF v_date > ’01−JAN−08’ THEN

V_salaire := V_salaire *1.15;

END I
F;
IF-THEN-ELSE

IF v_date > ’01−JAN−08’ THEN


V_salaire := v_salaire ∗ 1.15;
ELSE

V_salaire := v_salaire ∗ 1.05;

END I F ;


Langage PL/SQL : Commandes
Test conditionnel(2)

IF-THEN-ELSIF

IF v_nom =’PARKER’ THEN

V_salaire:= V_salaire * 1.15;

ELSIF v nom =’ SMITH ’ THEN

V_salaire:= V_salaire *1.05

END I F ;


Langage PL/SQL : Commandes
CASE CASE renvoie une valeur qui
vaut resultat1 ou resultat2 ou . . . ou
resultat par défaut
CASE selection
WHEN expression1 THEN resultat1 ou instruction 1
.
WHEN expression2 THEN resultat2 ou instruction 2
ELSE autre resultat ou autre instruction
END ;
Exemple de Case Dans une requette SQL

SELECT last_name, first_name ,job_id,


CASE
WHEN job_id='AD_PRES' THEN 'C est le président'
WHEN job_id='AD_VP ' THEN ' Vice Président chargé de la Administration'
WHEN job_id='FI_MGR' THEN ' Administrateur Financier'
WHEN job_id='FI_ACCOUNT' THEN ' Comptable'
WHEN job_id='AC_ACCOUNT' THEN ' Trésorier'
ELSE 'Autre fonction'
END
FROM employees;

Langage PL/SQL : Commandes
CASE : Exemple dans un bloc PL/SQL
Case Simple

Declare
LN$Num integer := 0 ;
Begin

LN$Num := '&entre' ;
CASE LN$Num
WHEN 1 Then dbms_output.put_line( ' premier' ) ;
WHEN 2 Then dbms_output.put_line( 'deuxieme' ) ;
WHEN 3 Then dbms_output.put_line( 'troisiem' ) ;
ELSE dbms_output.put_line( 'rang supérieur' ) ;
END CASE ;

End ;
/
Langage PL/SQL : Commandes
CASE : Exemple dans un bloc PL/SQL
Case de recherche
DECLARE
v_prix_vente NUMBER(9,2);
v_Value NUMBER(9,2) := &v_prix_vente;
v_taux_Commission NUMBER(3,2);
BEGIN
CASE
WHEN v_Value <= 100 THEN v_taux_Commission := 0.03;
WHEN v_Value <= 250 THEN v_taux_Commission := 0.05;
WHEN v_Value <= 1000 THEN v_taux_Commission := 0.08;
ELSE v_taux_Commission := 0.10;
END CASE;
DBMS_OUTPUT.PUT_LINE('Montant de la Commission est : '
|| TO_CHAR(v_taux_Commission * v_Value) || 'Dirhames');
END;

Pour le CASE l'omission de la clause ELSE provoque une erreur


dans s’il rencontre un cas non traité
Langage PL/SQL : Commandes
LOOP
Les boucles : LOOP
instructions ;
EXIT [WHEN condition ] ;
instructions ;
END LOOP ;

WHILE condition LOOP


instructions ;
END LOOP ;
Exemple
LOOP
Monthly_value := daily_value*31
EXIT WHEN monthly_value > 4000;
END LOOP ;

Obligation d’utiliser la commande EXIT


pour éviter une boucle infinie.

Langage PL/SQL : Commandes
Les boucles : LOOP
Exemple : Insérer 10 articles avec la date d’aujourd’hui.

declare
...
V_Date DATE;
V_compteur NUMBER( 2 ) := 1 ;
BEGIN
...
V_Date := SYSDATE;
LOOP
INSERT INTO article ( Artno , ADate )
VALUES ( v_compteur , v_Date ) ;
V_compteur := V_compteur + 1 ;
EXIT WHEN V_compteur > 1 0;
END LOOP;
...
END;/
Langage PL/SQL : Commandes
Les boucles : FOR
FOR indice IN [ REVERSE ] debut . . fin
LOOP Ne pas déclarer indice,
instructions ; il est d´eclaré implicitement.
END LOOP ;
La variable de boucle prend successivement les valeurs de
debut, debut + 1, debut + 2, . . ., jusqu’à la valeur fin .
On pourra également utiliser un curseur dans la clause IN

Le mot clef REVERSE à l’effet escompté.


Exemple

FOR ii IN REVERSE 1..15


LOOP
jj:=ii*31;
END LOOP


Langage PL/SQL : Commandes
GOTO

PL/SQL contient aussi la commade GOTO qui permet de


faire le branchement d’un programme d’un point un autre
point durant sont execution, ça syntaxe est :

GOTO <libelé>;
Langage PL/SQL : Commandes
GOTO
DECLARE
v_compteur NUMBER(2) := 1;
BEGIN
LOOP
v_compteur := v_compteur + 1;
IF v_compteur > 5 THEN
GOTO stop_processing;
END IF;
DBMS_OUTPUT.PUT_LINE('v_compteur est : '
|| v_compteur);
END LOOP;
<<stop_processing>>
DBMS_OUTPUT.PUT_LINE(' la valeur finale de
v_compteur final est ' || v_compteur );
END;
Langage PL/SQL : Commandes
Affichage
Activer le retour écran : set serveroutput on size 10000
Sortie standard : dbms_output.put_line (chaıne);
Concaténation de chaînes : opérateur ||

Exemple
Si on veut un retour chariot
on place le caractére suivant:
DECLARE chr(10)
i number (2);
BEGIN
FOR i IN 1 .. 5 LOOP ’
dbms_output.put_line('Nombre: ‘|| i );
END LOOP;
END ;
/

Le caractère / seul sur une ligne déclenche l’évaluation.


Langage PL/SQL : Commandes
Affichage
Exemple bis

DECLARE
compteur number(3);
i number(3);
BEGIN
SELECT COUNT( ∗ ) INTO compteur
FROM Etudiant ;
FOR i IN 1.. compteur LOOP
dbms_output.put_line(‘Nombre : ‘|| i);
END LOOP ;
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 le traitement dans la partie Exception


Gestion des Exceptions

Syntaxe
EXCEPTION

WHEN nom_exception1 THEN


instructions_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


Gestion des Exceptions

Syntaxe : en cas de déclaration définition

DECLARE
.....
nom_erreur EXCEPTION;
BEGIN
.....
IF anomalie THEN RAISE nom_erreur ;
.....
EXCEPTION
WHEN nom_erreur THEN traitement;
END;
Gestion d’une erreur : exemple
DECLARE
sal_nul EXCEPTION;
sal employees.salary%TYPE;
BEGIN
SELECT MAX(salary) INTO sal FROM employees;
IF sal > 100000
THEN RAISE sal_nul;
Else
dnms_output.put_line(‘vous pouvez augmenter le salaire de vos
employés’);
END IF;
EXCEPTION
WHEN sal_nul THEN
dnms_output.put_line(‘plafond dépassé’)
END;
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 (conversion d’un
caractère à un entité
ex: select * from employees where employee_id=‘Chaine_de_caractère‘
- lors d’une insertion
• 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 ( exp: taille de la variable petite que le nombre à affecter)
• ZERO_DIVIDE: au cas ou il y a une instruction qui effectue une division par Zéro
Exemple
Declare emp_Rec employees%ROWTYPE;
Begin

select *
into emp_Rec
from employees
where employee_ID = 777;
Exception
when No_Data_Found then
dbms_output.put_line(‘Aucune donnée retournée’);
when other then null;
End;
/
Aucune donnée retournée
Procedure PL/SQL terminé avec succès.
Déclaration d’une Exception
Declare
pas_comm EXCEPTION;
salaire employees.salary%TYPE;
commi employees.commition%TYPE;
numero employees.employee_id%TYPE;
Begin
Select salary, commition, employee_id into salaire, commi, numero
from employees where employee_id := &num_emp;
If commi = 0 or commi is null
then raise pas_comm
else traitement …
end if;
Exception When pas_comm then
dbms_output.put_line(‘ Pas de commission pour l’employé ID: ’|| numero);
End;

NB: 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’).

Exemple 1:
Declare
Begin
dbms_output.enable; // equivalente à set serveroutput on
dbms_output.put_line(‘SQLCODE: ‘ || to_char(SQLCODE));
dbms_output.put_line(‘SQLERRM: ‘ || SQLERRM);
End;
/
SQLCODE: 0
SQLERRM: ORA-0000: exécution normale, terminé avec succès
Test d’exécution avec SQLCODE et SQLERRM

Exemple 2:

Declare
v number;
Begin
select salary into v from employees;
dbms_output.enable; -- equivalente à set serveroutput on
Exception
when TOO_MANY_ROWS then
dbms_output.put_line('SQLCODE:'|| to_char(SQLCODE));
dbms_output.put_line('SQLERRM:' || SQLERRM);
End;
Test d’exécution avec SQLCODE et SQLERRM
Exemple 3: complet
Declare
pas_err EXCEPTION;
v number;
Begin
select salary into v from employees where employee_id=100;
if(SQLCODE=0) then raise pas_err;
end if;
Exception
when TOO_MANY_ROWS then
dbms_output.put_line('SQLCODE:'|| to_char(SQLCODE));
dbms_output.put_line('SQLERRM:' || SQLERRM);
when NO_DATA_FOUND OR TOO_MANY_ROWS then
dbms_output.put_line('SQLCODE:'|| to_char(SQLCODE));
dbms_output.put_line('SQLERRM:' || SQLERRM);
WHEN pas_err THEN
dbms_output.put_line('C''est corecte ');
End;
Les curseur

• Définition

– 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.
Quatre Étapes de traitement d’un curseur explicite

Les curseurs explicites sont traitées en suivant un modèle en


quatre étapes.

 Déclarer le CURSEUR: le curseur doit apparaitre dans la partie


déclaration de bloc pl/sql

 Ouvrir le CURSEUR : par l’instruction OPEN,


 Parcourir les ligne du CURSEUR : par l’ instruction FETCH.
 Fermer le CURSEUR : une instruction close .
Déclaration d’un curseur explicite
• Se fait dans la section Declare

Syntaxe : cursor nom_curseur is ordre_select


Exemple :

Declare
cursor dept_10 is select first_name , salary From
employees
where department_id= 10 order by salary;
nom employees .first_name%TYPE;
salaire employees . salary%TYPE;
Begin

End;
Ouverture d’un curseur : Open
• L’ouverture:
– 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 first_name , salary From employees
where department_id= 10 order by salary;
Begin
…;
open dept_10;
…;
End;
Traitement des lignes : Fetch

 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.


Exemple : Fetch

Declare
cursor dept_10 is select first_name , salary From employees
where department_id= 10 order by salary;
nom employees .first_name%TYPE;
salaire employees . salary%TYPE;
Begin
Open dept_10;
Loop
Fetch dept_10 into nom, salaire;
If salaire > 2500
then insert into résultat values (nom,salaire);
end if;
exit when salaire >= 5000;
end loop;

End;
Fermeture : close
• Syntaxe: Close nom_curseur;
• Action: libère la place de mémoire

Declare
cursor dept_10 is select first_name , salary From employees
where department_id= 10 order by salary;
nom employees .first_name%TYPE;
salaire employees . salary%TYPE;
Begin
Open dept_10;
Loop
Fetch dept_10 into nom, salaire;
If salaire > 2500 then
insert into résultat values (nom,salaire);
end if;
exit when salaire >= 5000;
end loop;
close dept_10;
End;
Exemple : close
Declare
Cursor c1 is select first_name, salary from employees order by
sal desc;
v_ename employees. first_name %TYPE;
v_sal employees.salary%TYPE;
Begin
open c1;
loop
fetch c1 into v_ename, v_sal;
insert into resultat values (v_sal, v_ename);
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
Utilisation des attribut du curseur
Pour manipuler les attribut d’un curseur implicite on utilise

SQL%Attribut

Exemples :
 SQL%FOUND ,
 SQL% ROWCOUNT

Pour manipuler les attribut d’ un curseur explicite on utilise

nom_curseur%Attribut

Exemples :

 nom_curseur%FOUND ,
 nom_curseur % ROWCOUNT)
Utilisation des attribut du curseur
Curseur Implicite : utilisation de l’attribut par SQL%Attribut

CREATE TABLE temp_Employee9 AS SELECT * FROM Employees;

DECLARE
e_DeptNumber employees.Department_id%TYPE :=9;
BEGIN
DELETE FROM temp_Employee9
WHERE Department_id <> e_DeptNumber;
IF SQL%FOUND THEN – Il y a des enregistrement
supprimmée
DBMS_OUTPUT.PUT_LINE('Nombre des enregistrement
supprimés: ‘ || TO_CHAR(SQL%ROWCOUNT));
ELSE
DBMS_OUTPUT.PUT_LINE('AUCUN enregistrement
n''supprimés ');
END IF;
END;
Exemple - %FOUND

Declare
cursor dept_10 is select first_name , salary From employees
where department_id= 10 order by salary;
nom employees .first_name%TYPE;
salaire employees . salary%TYPE;
Begin
Open dept_10;
Fetch dept_10 into nom, salaire;
While dept_10%FOUND Loop
If salaire > 2500 then 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 first_name , salary From employees
where department_id= 10 order by salary;
nom employees .first_name%TYPE;
salaire employees . salary%TYPE;
Begin
Open dept_10;
Loop
Fetch dept_10 into nom, salaire;
Exit when dept_10%NOTFOUND;
If salaire > 2500 then
bdms_output.put_line( nom ||’ ,’ ||salaire);
end if;
end loop;
close dept_10;
End;
Exemple - %ISOPEN

Declare
cursor dept_10 is select first_name , salary From employees
where department_id= 10 order by salary;
nom employees .first_name%TYPE;
salaire employees . salary%TYPE;
Begin
If not(dept_10%ISOPEN) then
Open dept_10;
end if;
Loop
Fetch dept_10 into nom, salaire;
Exit when dept_10%NOTFOUND;
If salaire > 2500 then
insert into résultat values (nom,salaire);
end if;
end loop;
close dept_10;
End;
Exemple - %ROWCOUNT

Declare
cursor dept_10 is select first_name , salary From employees
where department_id= 10 order by salary;
nom employees .first_name%TYPE;
salaire employees . salary%TYPE;
Begin
Open dept_10;
Loop
Fetch dept_10 into nom, salaire;
Exit when dept_10%NOTFOUND or dept_10%ROWCOUNT > 15;
If salaire > 2500
then insert into résultat values (nom,salaire);
end if;
end loop;
close dept_10;
End;
Boucle LOOP Exit when pour un curseur

declare Dans cette boucle on est


cursor c is obligé d’utiliser :
select department_id, first_name from employees
where department_id = 10; Open
Name employees.first_name%type;
Dept employees. department_id%type;
LOOP
Begin FETCH
Open c; CLOSE
LOOP Exit when
FETCH c into dept, name ;
Exit when c%NOTFOUND ;
dbms_output.put_line(name );

END LOOP;
CLOSE c;
end;
Boucle WHILE pour un curseur

declare
cursor c is select department_id, Utiliser WHILE élimine le
first_name from employees besoin de l’instruction EXIT
where department_id = 10; WHEN en intégrant l'utilisation
Name employees.first_name%type; de l'attribut % FOUND.
Dept employees.department_id%type;
Begin 2 instructions FETCH (Une
Open c; juste avant le while et l’autre
FETCH c into dept, name ; avant le END LOOP)
while c%FOUND loop
dbms_output.put_line(name);
FETCH c into dept, name ;
End loop;
CLOSE c;
end;
Boucle FOR pour un curseur
‰ Elle simplifie la programmation car elle évite d’utiliser explicitement
les instruction open, fetch, close, exit
‰ En plus elle déclare implicitement une variable de type « row »
associée au curseur
declare
cursor c is
select department_id, first_name from employees
where department_id = 10;
begin
FOR emp IN c LOOP
dbms_output.put_line(emp.first_name);
END LOOP;
end;
Mise à jour d’une table -La clause WHERE CURRENT OF

La clause WHERE CURRENT OF peut être utilisée pour


exécuter des instructions DML sur la ligne actuelle du curseur.

 Cela facilite les mises à jour précises.

Pour utiliser WHERE CURRENT OF, le curseur doit être créé


avec une clause FOR UPDATE.

On l’utilise avec UPDATE , DELETE


Exemples -La clause WHERE CURRENT OF

DECLARE
DECLARE
CURSOR moncurseur IS SELECT Employee_ID , salary CURSOR moncurseur IS SELECT
FROM employees FOR UPDATE; Employee_ID FROM employees FOR
e_Record moncurseur%ROWTYPE; UPDATE;
BEGIN BEGIN
OPEN moncurseur;
FOR c_tmp IN moncurseur LOOP
LOOP
IF c_tmp.Employee_ID = ‘102' THEN
FETCH moncurseur INTO e_Record;
EXIT WHEN moncurseur %NOTFOUND; UPDATE employees SET
IF e_Record.salary > 40000 THEN salary= salary + 350
DELETE FROM Employees WHERE CURRENT OF moncurseur;
WHERE CURRENT OF moncurseur; END IF;
END IF;
END LOOP;
END LOOP;
COMMIT;
CLOSE moncurseur;
END; END;
/
Curseur avec des paramètres
A votre avis, le code suivant est-il valide ?
declare
n NUMBER := 14;
CURSOR C IS SELECT * FROM EMPLOYEES WHERE employee_id>= n ;
ROW C%rowType ;
BEGIN
FOR CUR IN C LOOP
DBMS_OUTPUT.PUT_LINE ( CUR.FIRST_NAME) ;
END LOOP ;
END ;
/

Non. La requête d’un curseur ne peut pas contenir de variables dont les
valeurs ne sont pas fixées.
Pourquoi ? Parce que les valeurs des ces sont susceptibles de changer entre
la déclaration du curseur et son ouverture.
Le remède est un curseur paramétré.
Curseur avec des paramètres

Vous pouvez modifier les lignes de données renvoyées dans un jeu de


résultats en généralisant code PL/SQL grâce à l'utilisation des paramètres.
Les paramètres peuvent être utilisés pour spécifier les critères de sélection
de la requête lorsque vous ouvrez le curseur.
Déclarer curseurs entre parenthèses par nom et type de données, comme
indiqué ici. Lorsque vous avez besoin de spécifier plusieurs parameter pour
un curseurs, séparez les entrées par une virgule.
 La syntaxe est :

CURSOR mycursor (param1 NUMBER, param2, type2 ....,


paramn typen ) IS SELECT ...... FROM tables WHERE
(condition sur les parameters)
Curseur avec des paramètres

Ouverture
On ouvre un curseur paramétré en passant en paramètre
les valeurs des variables :
OPEN Nom_curseur ( liste de sparamètres )

Exemple OPEN enfants ( 1 ) ;

Lecture par la Boucle FOR


FOR variable IN nom_curseur ( liste paramètre s )
LOOP
/∗ instructions ∗/
END LOOP ;
Passer des paramètres à un curseur

Exemple Recapitulatif

Declare
CURSOR mycursor (param1 number, param2 number) is select Employee_ID ,
salary
from employees where employee_id between param1 and param2;
e_Record mycursor%rowtype;
BEGIN
OPEN mycursor('102','110');
FETCH mycursor INTO e_Record;
loop
DBMS_OUTPUT.PUT_LINE('Salare de ' || e_Record.Employee_ID || ': ' ||
e_Record.Salary ||' $');
FETCH mycursor INTO e_Record;
exit when mycursor%notfound;
end loop;
CLOSE mycursor;
/
Exercices :

1) En utilisant un Curseur, Écrivez un programme PL/SQL qui


calcule la moyenne des salaires des employés dont la date de
recrutement est entre 01/01/2002 et 01/01/2005.
Comparer avec la requête ci-dessous, vous devez trouver la
même chose
(SELECT avg(salary) FROM employees
WHERE ( to_date(hire_date,'DD/MM/YY') between '01/01/02' and
'01/01/05' );

2) Refaire la question 5 en passant les deux dates 01/01/2002 et


01/01/2005. En paramètre de curseur
Procédures et Fonctions stockées

Objectifs:

Décrire les différentes utilisation des procédure

et fonctions

Créer des procédures et fonction stockées

Appeler une procédure et une fonction

Supprimer une procédure et une fonction


Procédures stockées

Tout comme n’importe quel autre langage procédural, PL / SQL a des


blocs de code qui sont appelées procédures.

Vous pouvez appeler ces procédures par les autres blocs de code,
ou directement à partir de SQL * Plus (ou par un autre programme
client).
Avant de créer des procédure il vous faut avoir les droits
nécessaire

GRANT CREATE PROCEDURE TO utilisateur_désiré;


Procédures stockées
Un Simple exemple de procédure

CREATE or replace PROCEDURE Bonjour IS


BEGIN
DBMS_OUTPUT.PUT_LINE(‘Bonjour Tout le monde’ );
END;

Appel de la procédure

Dans un autre bloc PL/SQL Par commande SQL*Plus


BEGIN exec Bonjour();
Bonjour(); Ou bien
END; Call Bonjour();
Procédures stockées
Syntaxe générale

CREATE OR REPLACE
PROCEDURE nom_procedure ( paramètres IN , OUT ) IS
BEGIN
Corps_de_la_procedure
END;

nom_procedure : est le nom de la procédure, il doit être significatif

Corps_de_la_procedure: est une suite d’instruction PL/SQL qui


définissent la suite logique de la procédure
Procédures stockées
Paramètres
Les paramètres sont optionnels dans les procédure, dans
l’exemple que nous avons déjà vu il n y a pas de paramètres

CREATE OR REPLACE
PROCEDURE HELLOWORLD IS
BEGIN
DBMS_OUTPUT.PUT_LINE(’Hello World!’);
END;

Où cas où il y a des paramètres on les introduit comme on le fait


lors de la création des tables  (nom_param type )
Exemple ( N int , titre varchar)
Procédures stockées
1 seul paramètre: Exemple

Nous allons écrire une simple procédure admettant un seul


paramètre

CREATE OR REPLACE
PROCEDURE DISPN (N INT) IS
BEGIN
DBMS_OUTPUT.PUT_LINE(‘N est : ‘ || N);
END;

Cette procédure affiche la valeur de nombre N


passé en paramètre

SQL>call DISPN(555)
N est : 555
Procédures stockées
Plusieurs paramètres: Exemple

CREATE OR REPLACE
PROCEDURE DISP_AB (A INT, B INT) IS
BEGIN
DBMS_OUTPUT.PUT_LINE(’A + B = ’ || (A + B));
DBMS_OUTPUT.PUT_LINE(’A * B = ’ || (A * B));
END;

SQL> CALL DISP_AB(17,23);


A + B = 40
A * B = 391
Procédures stockées
paramètres: Exemple avec une chaine de caractère

CREATE OR REPLACE
PROCEDURE DISP_NAME (NAME VARCHAR) IS
BEGIN
DBMS_OUTPUT.PUT_LINE(’Hi ’ || NAME || ’!’);
END;

SQL> CALL DISP_NAME(’Billal Merssi’);


Hi Billal Berssi !
Procédures stockées
Options : IN, OUT, IN OUT

Quand on ne fait pas d’option les paramètres sont


considérer comme IN par défaut

IN : pour un paramètre en entrer  il est généralement


placé après l’affectation ( := )

OUT: pour un paramètre qui va recevoir des données dans


le corps de la procédure il est généralement placé avant
l’affectation ( := )

IN OUT: pour des paramètre qui sont à la fois des IN et des
OUT
Procédures stockées
Options : IN, OUT, IN OUT: exemple

CREATE OR REPLACE
PROCEDURE SUM_AB (A INT, B INT, C OUT INT) IS
BEGIN
C := A + B;
END;
Faites appel à la procédure dans un bloc PL/SQL !

DECLARE
R INT;
BEGIN
SUM_AB(23,29,R);
DBMS_OUTPUT.PUT_LINE(’SUM IS: ’ || R);
END;
Procédures stockées
Exemple avec : IN OUT

CREATE OR REPLACE
PROCEDURE DOUBLEN (N IN OUT INT) IS
BEGIN
N := N * 2;
END;

Faites appel à la procédure dans un bloc PL/SQL !


DECLARE
R INT;
BEGIN
R := 7;
DBMS_OUTPUT.PUT_LINE(’BEFORE CALL R IS: ’ || R);
DOUBLEN(R);
DBMS_OUTPUT.PUT_LINE(’AFTER CALL R IS: ’ || R);
END;
Procédures stockées
Exemple : Créer une procédure qui permet de baisser le prix d'un produit
de la table: Produit (Nump, nomp, pu, qstock)

CREATE PPROCEDURE baisse_prix( nprod IN NUMBER, Taux IN


NUMBER ) IS
BEGIN
if Taux <1 then
UPDATE produit SET PU= PU* ( 1 - Taux) WHERE Nump= nprod ;
end if;
END
Fonctions stockées

Une fonction est un bloc PL/SQL nommé qui peut accepter des
paramètres et être appelé.

En règle générale, vous utilisez une fonction pour calculer une
valeur

Une fonction doit comporter une clause RETURN dans l'en-tête,


et au moins une instruction RETURN dans la section exécutable.

Les fonctions peuvent être stockées en tant qu'objets de schéma


dans la base de données en vue d'exécutions répétées.
Fonctions stockées

Syntaxe pour créer une fonction

CREATE [OR REPLACE] FUNCTION num_fonction


[( param1 [mod1] datatype1, param2 [mod2] datatype
2, ….)]
RETURN datatype
IS|AS
Block PL/SQL ;
Fonctions stockées

Description des paramètres


Paramètre Description
function_name Nom de la fonction.
parameter Nom d'une variable PL/SQL dont la valeur est transmise à
la fonction.
mode Type du paramètre. Seuls les paramètres IN doivent être
déclarés.
datatype Type de données du paramètre.
RETURN datatype Type de données de la valeur RETURN qui doit être fournie
par la fonction.
PL/SQL block Corps de la procédure qui définit l'action exécutée par la
fonction.
Fonctions stockées
Exemple de création d’une fonction stockée
get_salaty.sql
create or replace function get_sal
(p_id in employees.employee_id%type)
return number
is
v_salary employees.salary%type:=0;
begin
select salary into v_salary from employees where
employee_id=p_id;
return v_salary;
end ;
/
Fonctions stockées
Exemple suite
1- Créez le script pour définir la fonction get_salary. avec un
paramètre IN pour renvoyer une valeur numérique.

2- Exécutez le script pour créer la fonction get_salary.

3- Appelez la fonction dans une expression PL/SQL, pour elle


renverra une valeur à l'environnement appelant, ( par exemple
affichage la valeur )

Remarque:
- La section de traitement des exceptions peut également
contenir une instruction RETURN.
Fonctions stockées

Appel d'une procédure ou fonction

SQL> Declare
A employees.employee_id%type;
S number
BEGIN
A := &Numero_de_employe; --lire à partir du clavier
S :=get_sal (A);
dbms_output.put__line(S );
END ;
/
Fonctions stockées
Appel d'une procédure ou fonction (suite)
Exemple 2
-Créer une fonction TAX qui sera appelée à partir d'une instruction SELECT.
- La fonction accepte un paramètre NUMBER et renvoie la taxe après avoir
multiplié la valeur du paramètre par 0,08.
Create or replace function tax( p_value in number) Return number is
Begin
Return (p_value * 0.08);
End tax;
/

- Appelez la fonction TAX au sein d'une interrogation affichant:


le code, le nom, le salaire et le prélèvement fiscal de l'employé.

SELECT employee_id, tax(salary) FROM employees WHERE


tax(salary)>(SELECT MAX(tax(salary)) FROM employees WHERE
department_id = 30) ORDER BY tax(salary) DESC;
Fonctions stockées
Restriction d’Appel d'une fonction
Exemple de restrictions
CREATE OR REPLACE FUNCTION query_call_sql(a NUMBER) RETURN
NUMBER IS s NUMBER;
BEGIN
SELECT salary INTO s FROM employees WHERE employee_id=170;
RETURN (s + a);
END;
/

Lorsqu'elle est appelée depuis l'instruction UPDATE suivante, la fonction


query_call_sql ci-dessus renvoie un message d’erreur, car on est entrain
d’extraire la fonction un enregistrement encours de mise à jour

UPDATE employees SET salary=query_call_sql(100)


WHERE employee_id = 170;
Fonctions stockées

Modification d’une procédure ou fonction


Si la base de données évolue, il faut recompiler les procédures
existantes pour qu’elles tiennent compte de ces modifications
 
La commande est la suivante:
ALTER { FUNCTION | PROCEDURE } nom COMPILE
 
Exemple:

ALTER PROCEDURE Baisse_prix COMPILE;

ALTER FUNCTION NomClient COMPILE;


Fonctions stockées
Supprimer des fonctions et procédure
 Lorsqu'une fonction stockée n'est plus nécessaire, vous
pouvez la supprimer en utilisant une instruction SQL
Pour supprimer une fonction stockée en exécutant
la commande SQL
DROP FUNCTION nom_fonction
DROP PROCEDURE nom_procedure;

 La commande CREATE OR REPLACE est comparé à


DROP puis CREATE
Procédures stockées

CREATE OR REPLACE
Que signifie CREATE OR REPLACE ?

Créer l’objet s’il n’existe pas

s’il existe  remplacer le corps de l’objets par ce


nouveau corps
Est-ce qu’on peut la remplacer par:
Supprimer l’objet
Puis NON question de droit et privilèges
Créer l’objet Sauf si vous avez les droit
?
Les sous-blocs

•Un bloc PL/SQL peut contenir un sous bloc:

Declare
Variables
Begin
…..
Declare
Variables
Begin
….
End;
…..
End;
Les sous-blocs

Exemple

Declare
a number; b varchar2(30); c number;
Begin
a:=10; b:='Imagination'; c:= 20;
Declare
a number; b varchar2(30); d number;
Begin
d:=c+5;
a:=40 ;b:='programmation';
End;
b:=b||' Esprit'; a:=a+d;
dbms_output..put__line(a||'' ''||b||'' ''||c));
End;
PACKAGES DANS PL/SQL

- C’est quoi Un Package


- Création de Package
- Comment utiliser les package
- Avantage de Package
C’est quoi PACKAGES
Package : est un ensemble des procédures , fonction,
variable et instructions SQL qui sont rassemblés et
stockés dans la base de données

Une collection d'objets PL / SQL qui sont logiquement


regroupés pour former une seule unité
Ils peuvent contenir:

 Procédures, fonctions
 Curseurs, variables, des constantes
 tableaux
 Exceptions

Typiquement, ils peuvent contenir des règles et des


procédures pour traiter les commandes d'achat, par exemple.
La structure de Package

Applications Package
Variables globales et publique Base données

Spec

BODY

Variables locales et privées


La structure de Package
A deux parties:
Spécification de package
 Déclare procédures publiques etc.
 D'autres programmes peuvent y accéder en dehors du
package
Corps package Body
Met en œuvre les procédures, fonctions ect ..publiquement ,
mais peut également les spécifier comme privée
Les unités privés ne sont accessibles que dans la portée de
package lui-même
Toutes les unités déclarées dans les spécifications doivent être
mises en œuvre dans la partie Body
La structure de Package
Spécification de package Corps de package BODY
[CREATE [OR REPLACE] PACKAGE
CREATE [OR REPLACE] PACKAGE
BODY package_name
package_name
{IS | AS}
[AUTHID {IS | AS}
[collection_type_definition ...]
[collection_type_definition ...]
[record_type_definition ...]
[record_type_definition ...]
[subtype_definition ...]
[subtype_definition ...]
[collection_declaration ...]
[collection_declaration ...]
[constant_declaration ...]
[constant_declaration ...]
[exception_declaration ...]
[exception_declaration ...]
[object_declaration ...]
[object_declaration ...]
[record_declaration ...]
[record_declaration ...]
[variable_declaration ...]
[variable_declaration ...]
[cursor_body ...]
[cursor_spec ...]
[function_spec ...]
[function_spec ...]
[procedure_spec ...]
[procedure_spec ...]
[BEGIN
[call_spec ...]
sequence_of_statements]
END [package_name];
END [package_name];]
La structure de Package
Exemple de déclaration de package

CREATE OR REPLACE PACKAGE nom_ package


IS
PROCEDURE augm_sal(p1 NUMBER, p2 NUMBER);
FUNCTION dep_bal (num_dept IN NUMBER)
RETURN NUMBER;
END nom_ package;
Exemple de déclaration de package (suite)

CREATE OR REPLACE PACKAGE BODY package_name


IS
PROCEDURE augm_sal (p1 NUMBER, p2 NUMBER)
IS
BEGIN
update emplyees set salary=salary*1.1 where
department_id=p2;
END augm_sal;
---------------------------------------------
FUNCTION div_bal (num_dept IN NUMBER)
RETURN NUMBER
IS
bal number;
BEGIN
select sum(salary) into bal from emplyees where
department_id= num_dept ;
RETURN bal;
END div_bal;
END package_name;
L’intérêt de Package
On vous a demandé de générer un nombre aléatoire entre 100
et 1000, Si ce nombre est paire insérer le dans la table tab_paire
s’il est impaire insérer le dans la table tab_impaire
Declare
X number
Begin On peut vous poser aussi
-- générer un nombre aléatoire entre 100 et 1000 une autre question
X:=dbms_random.value(100,1000) 67 est t’il paire ?
--code pour determiner si le nombre est paire ou
non
If (mode(x,2)=0) then ( x est paire)
Else ( x est impaire)
--code pour insertion
If (x est paire) then insert into tab_paire
Else
insert into tab_impaire
End if
End;
L’intérêt de Package

 Notre programme peut être décomposer en 3 parties

1-Générer une valeur aléatoire


2- Tester si cette valeur est paire ou non
3- Insérer la valeur dans la table adéquate

On va donc représenter chaque partie comme étant une


fonction ou procédure

Rassembler toute ces partie dans un seul conteneur


Ce conteneur est appelé PACKAGE
Package
Spécifications BODY
Create or replace package body XYZ is
Function num_aleatoire ( param1 number ,
Create Or replace package XYZ is
param2 number )
Function num_aleatoire
return number
( param1 number , param2
Is
number ) return number;
V_alea number ;
Function c_paire ( Param
Begin
number) return boolean ;
V_alea:= round(dbms_random.value(param1,
Procedure insertion ( par1
param2));
number, par2 number );
Return V_alea;
End XYZ ;
End num_aleatoire ;
Function c_paire ( Param number) return boolean
Is
begin
If ( mod(Param,2)=0) then return TRUE;
Else return FALSE;
End if ;
End c_paire ;…
BODY (suite)
Procedure insertion ( par1 number, par2 number ) is
num_ale number ;
Begin
num_ale := num_aleatoire(par1, par2);
If (c_paire(Num_ale)) then
insert into tab_paire values (num_ale);
Else insert into tab_impaire values(num_ale);
End if;
Commit;
End insertion ;
End XYZ ;

Comment exécuter le package ?


Xyz.insertion( 200,700);
Xyz. c_paire(67)
Xyz. num_aleatoire(3 , 34);
Variables globales/ Variables locales
CREATE OR REPLACE PACKAGE pack1 IS
V1 NUMBER:=1; ------------Variable Globale
Procedure proc1;
End pack1;
/

CREATE OR REPLACE PACKAGE BODY pack1 IS


V2 NUMBER:=2; ------------Variable Globale
Procedure proc1 IS
V3 NUMBER:=3; ------------Variable locale
BEGIN
v1:=v1+1;
v2:=v2+2;
v3:=v3+3;
DBMS_OUTPUT.PUT_LINE(‘v1 = ‘||v1);
DBMS_OUTPUT.PUT_LINE(‘v2 = ‘||v2);
DBMS_OUTPUT.PUT_LINE(‘v3 = ‘||v3);
END proc1;
END pack1;
Variables globales/ Variables locales
CREATE OR REPLACE PACKAGE pack1 IS
V1 NUMBER:=1; ------------Variable Globale
Procedure proc1;
Execution
End pack1; 1er 2em 3 eme
CREATE OR REPLACE PACKAGE BODY pack1 IS v1 2 3 4
V2 NUMBER:=2; ------------Variable Globale
v2 4 6 8
Procedure proc1 IS
V3 NUMBER:=3; ------------Variable locale v3 6 6 6
BEGIN
v1:=v1+1;
v2:=v2+2;
v3:=v3+3;
DBMS_OUTPUT.PUT_LINE(‘v1 = ‘||v1);
DBMS_OUTPUT.PUT_LINE(‘v2 = ‘||v2);
DBMS_OUTPUT.PUT_LINE(‘v3 = ‘||v3);
END proc1;
END pack1;

Execute pack1.proc1 – faites le 3fois !


Pragma SERIALLY_REUSABLE
Provoque le / SQL PL exécution de jeter l'état d’écraser l’état de
package . Donc instanciation se produit chaque fois qu'il est cité
Pragma serially_reusable doit être appliqué à la fois pour la
spécification et le CORPS
Maintenant, l'exécution de 3 fois le code précédent seraient les
suivants

CREATE OR REPLACE PACKAGE pack1 IS


Pragma serially_reusable;
V1 NUMBER:=1;
Procedure proc1;
End pack1;
Pragma SERIALLY_REUSABLE
CREATE OR REPLACE PACKAGE pack1 IS
Pragma serially_reusable; --- Lametre ICI
V1 NUMBER:=1; - -----------Variable Globale
Procedure proc1; Execution 3fois !
End pack1; 1er 2em 3 eme
/
CREATE OR REPLACE PACKAGE BODY pack1 IS v1 2 2 2
Pragma serially_reusable;---- Et ICI
V2 NUMBER:=2; ------------Variable Globale v2 4 4 4
Procedure proc1 IS
v3 6 6 6
V3 NUMBER:=3; ------------Variable locale
BEGIN
v1:=v1+1;
v2:=v2+2;
v3:=v3+3;
DBMS_OUTPUT.PUT_LINE(‘v1 = ‘||v1);
DBMS_OUTPUT.PUT_LINE(‘v2 = ‘||v2);
DBMS_OUTPUT.PUT_LINE(‘v3 = ‘||v3);
END proc1;
END pack1;
Comment supprimer le package ?
 Pour la suppression des specification et body

• DROP PACKAGE nom_package


 Pour la suppression de body seulement

• DROP PACKAGE BODY nom_package


Avantages de Package

Les packages offrent plusieurs avantages:

La modularité,

La conception plus facile d'application,

Encapsulation des données et méthodes

Meilleure performance.
Avantages de Package

La modularité:
Les Package vous permettent d'encapsuler des types logiquement liés,
des éléments et des sous-programmes dans un module PL / SQL
nommée. Chaque package est facile à comprendre, et les interfaces
entre les packages sont simples, clairs et bien définis. Ceci facilite le
développement d'applications.
Avantages de Package
La conception plus facile d'application:
Lors de la conception d'une application, Vous n’avez besoin
initialement que de l'information sur d'interface des spécifications
du package . Vous pouvez coder et compiler une spécification sans
son corps (body). Puis, les sous-programmes référençant le
package peuvent être compilées ainsi au fur et à mesure . Vous
n’êtes pas obligés de définir immediatement tout les organes du
package même s’il sont déclarer dans la partie spécification
Avantages de Package
Encapsulation des données et méthodes
Avec les packages, vous pouvez spécifier quels sont les types, les
éléments et les sous-programmes publiques (visibles et accessibles)
ou ceux privés (cachés et inaccessibles).
Par exemple, si un package contient 4 sous-programmes, 3 public et
1 privé. Le package cache la mise en œuvre du sous-programme
privé de sorte que seul le package (et non toute l’ application) est
affecté en cas de changement de sa mise en œuvre. Cela simplifie la
maintenance et l'amélioration.
- Ils permettent le over loading : déclaration du plusieurs fonctions
et procédure avec le même nom et paramètres différents
Avantages de Package

Meilleure performance.
Lorsque vous appelez un sous-programme de package pour la
première fois, l'ensemble du package est chargé en mémoire(SGA).
Ainsi, les appels plus tard des autre sous-programmes de package
ne nécessitent aucune E/S disque.
En outre, les package stoppent les dépendances en cascade en
évitant toute recompilation inutile. Par exemple, si vous changez la
mise en œuvre d'une fonction du package , Oracle n'a pas besoin de
recompiler touts les autres sous-programmes même ceux qui lui
font appel, car ils sont indépendant de corps(body) du package .
Les Déclencheurs (Triggers) DANS PL/SQL

 Définir un Déclencheur (Trigger)


 Décrire les différents types de triggers
 Décrire les triggers de la base de données et leurs utilisation
 Créer des triggers
 Décrire les régles de déclenchement des triggers
 Supprimer les triggers
Les Déclencheurs (Triggers) DANS PL/SQL
Définition :
Un Trigger : Est un bloc ou d'une procédure PL / SQL
associé à une table, une vue, un schéma ou à une
donnée qui s’exécute implicitement(automatiquement)
à chaque fois qu'un événement particulier a lieu.

Type de Triggers

Triggers d’application: est déclenché chaque fois qu'un événement


se produit avec une application particulière

Triggers base de données: est déclenché chaque fois qu'un


événement de données (comme DML) ou un événement du système
(telles que l'ouverture de session ou d'arrêt) se produit sur un
schéma ou base de données
Les Déclencheurs (Triggers) DANS PL/SQL
Directives pour la conception Triggers
Vous pouvez concevoir les Triggers pour :
 Effectuer des actions connexes
 Centraliser des opérations globales

Vous ne devez pas concevoir Triggers Si :


 Leurs fonctionnalités est déjà intégrée dans le serveur Oracle
 ils dupliquent la même tache d'autres Triggers

Vous pouvez créer des procédures stockées et les invoquer dans un


Triggers, si le code PL / SQL est très longue.

L'utilisation excessive de Triggers peut entraîner des


interdépendances complexes, ce qui peut être difficile à maintenir dans
de grandes applications
Les Déclencheurs (Triggers) DANS PL/SQL
CREATION de TRIGGER
CREATE [OR REPLACE] TRIGGER nom_trigger
Quand
Evenement 1 [OR Evenement 2 OR Evenement3]
ON nom_Objet
[[REFERENCING OLD AS old | NEW AS new]
FOR EACH ROW // pour chaque ligne
[WHEN (condition)]]
Begin
Corps de trigger (PL/SQL bloc )
End;
Les Déclencheurs (Triggers) DANS PL/SQL
Les composantes de la syntaxe de creation de Triggers :

nom_trigger : unique pour les trigger du meme schéma.


Quant : indique quand le trigger va se déclancher en fonction
avec l’evenement qui va se passer dans la BD :

BEFORE, AFTER, et INSTEAD OF.

Evenement : identifie l’opération DML qui provoque le declenchement

INSERT, UPDATE [OF column], et DELETE.

Nom_objet : indique la table ou la vue associés au trigger.


Les Déclencheurs (Triggers) DANS PL/SQL
Les composantes de la syntaxe de creation de Triggers
(Suite) :
Pour le trigger ligne vous pouvez specifier :

REFERENCING : pour corréler les valeur old et new pour la ligne


courante (par default OLD et NEW)
FOR EACH ROW : pour indiquer que le trigger est une trigger ligne
WHEN : clause pour appliquer un filtre, qui sera mis entre
parentheses,
Corps de trigger : C’est l’action à efectuer par le trigger, qui est
implementé comme suit:
 Un bloc anonyme PL/SQL (DECLARE ou
BEGIN, et un END)
 Appel à une procedure/fonction stoquée ou bien
un package (CALL , EXECUTE)
Les Déclencheurs (Triggers) DANS PL/SQL
Types de Triggers DML
Le type de trigger DML determine Si le Corps de trigger s’exécute
pour chaque ligne ou une seule fois pour l’evenement déclanchant:
Type 1: Les trigger de table (Trigger STATEMENT) :
Excecutés une fois pour l’evenement déclanchante
C’est le type par défaut des triggers
Déclanchés meme s’il n y a aucune ligne affécté par l”evnement
Type 2: Les Triggers ligne :
Exécutés « séparément » pour chaque ligne affécté par l”evnement
Ne sont pas executé Si l’evenement n’a affecté aucun ligne
Sont indiqués en précisant la clause FOR EACH ROW
Les Déclencheurs (Triggers) DANS PL/SQL

Quand le trigger se déclence ?

BEFORE: (Avant) Executer le trigger avant de proceder à


l’evenement DML sur la table.
AFTER (Aprés) Executer le trigger aprés l’evenement DML sur la
table.
INSTEAD OF: (au lieu de) Executer le corps de trigger au lieu de
l’évenement. Ceci est utilisé pour les VUES qui ne sont pas
modifiable

Note: Si plusieurs Triggers sont définis pour un meme objet leurs


déclancement est arbitraire
Les Déclencheurs (Triggers) DANS PL/SQL
Séquence de déclenchement de Trigger
Utilisez la séquence de déclenchement suivante pour un
Trigger sur une table quand une seule ligne est manipulé:
INSERT INTO departments (department_id,department_name,
location_id) VALUES (400, 'CONSULTING', 2400);

BEFORE avant le trigger tables


.…
BEFORE avant le trigger ligne

… … … AFTER Aprés le trigger ligne

AFTER Aprésle trigger tables


Les Déclencheurs (Triggers) DANS PL/SQL

UPDATE employees SET salary = salary * 1.1


WHERE department_id = 30;

BEFORE avant le trigger tables

BEFORE (avant) le trigger ligne

AFTER (aprés) le trigger ligne

….
….
BEFORE (avant) le trigger ligne

AFTER (aprés) le trigger ligne

AFTER (Aprés )le trigger tables


Les Déclencheurs (Triggers) DANS PL/SQL
Les types d’événement et le corps de triggers

Événement de trigger :

Determine quel Order DML va déclencher l’execution de


trigger. Ils sont :
INSERT
UPDATE [OF column]
DELETE

Corps de triggers :

Détermine l'action a effectuée


Est-ce un bloc PL / SQL ou un appel à une procédure
Les Déclencheurs (Triggers) DANS PL/SQL
Création d’un trigger pour sécurisé l’insertion dans la table employees
Application
table EMPLOYEES
INSERT INTO EMPLOYEES...;

trigger SECURE_EMP

CREATE OR REPLACE TRIGGER secure_emp


BEFORE INSERT ON employees
BEGIN
IF (TO_CHAR(SYSDATE,'DY') IN ('DIM.','SAM.')) OR
(TO_CHAR(SYSDATE,'HH24:MI') NOT BETWEEN '08:00' AND ‘18:00')
then
RAISE_APPLICATION_ERROR(-20500,'Vous ne pouvez inserer dans la table
employes que durant les heures de travail');
END IF;
END;
Les Déclencheurs (Triggers) DANS PL/SQL
Testons notre trigger

INSERT INTO employees (employee_id, last_name,


first_name, email, hire_date, job_id, salary, department_id)
VALUES (300, 'Smith', 'Rob', 'RSMITH', SYSDATE, ‘'IT_PROG', 4500, 60);

Rapport d'erreur -
Erreur SQL : ORA-20500: Vous ne pouvez inserer dans la table
employes que durant les heures de travail
ORA-06512: at "HR.SECURE_EMP", line 4
ORA-04088: error during execution of trigger 'HR.SECURE_EMP'
Les Déclencheurs (Triggers) DANS PL/SQL
Utilisation de prédicats conditionnels
CREATE OR REPLACE TRIGGER secure_emp BEFORE
INSERT OR UPDATE OR DELETE ON employees
BEGIN
IF (TO_CHAR(SYSDATE,'DY') IN ('SAM.','DIM.')) OR (TO_CHAR(SYSDATE,'HH24') NOT BETWEEN '08'
AND '18') THEN
IF DELETING THEN RAISE_APPLICATION_ERROR(-20502, 'Vous ne pouvezSupprimer dans la table
employes que
durant les heures de travail');

ELSIF INSERTING THEN RAISE_APPLICATION_ERROR(-20500, 'Vous ne pouvez inserer dans la table


employes que
durant les heures de travai.');

ELSIF UPDATING('SALARY') THEN RAISE_APPLICATION_ERROR(-20503, 'Vous ne pouvez changer


dans la table employes que durant les heures de travai.');
ELSE RAISE_APPLICATION_ERROR(-20504, 'Vous ne pouvez changer dans la table employes que
durant les heures Normales ');
end if;
END IF;
END;
Les Déclencheurs (Triggers) DANS PL/SQL
Utilisation des qualificatifs : OLD et NEW
Il ne sont utilisé que pour le trigger ligne
lorsqu’un trigger ligne est mentionné à
INSERT : Pas d’accès à l’élément OLD (qui n’existe pas)
UPDATE : Accès possible à l’élément OLD et NEW
DELETE : Pas d’accès à l’élément NEW (qui n’existe plus)
Exemple:
CREATE OR REPLACE TRIGGER audit_emp_values
AFTER DELETE OR INSERT OR UPDATE ON employees
FOR EACH ROW
BEGIN
INSERT INTO
audit_emp(user_name, time_stamp, id, old_last_name, new_last_name, old_title,
new_title, old_salary, new_salary)
VALUES (USER,
SYSDATE, :OLD.employee_id, :OLD.last_name, :NEW.last_name, :OLD.job_id, :NEW.job_id
, :OLD.salary, :NEW.salary);
Les Déclencheurs (Triggers) DANS PL/SQL
Trigger ligne avec OLD et New
(1/4)
Soit le schéma suivant:
- Stock (#Idproduit, nom_prod,qtt_produit)
- Commande((#Idproduit, #id_client,qtt_commande)
CREATE or replace TRIGGER Ventes_trig AFTER INSERT ON commandes
REFERENCING NEW AS nouv
FOR EACH ROW
begin
UPDATE Stocks
SET Stocks.qtt_produit = Stocks.qtt_produit - :nouv.qtt_commande
WHERE Stocks.IDproduit = :nouv.IDproduit ;
end;

Faisons un test ensemble!: insert into commandes values ( 111 , 555 , 100);
Question : Que ce que va se passer si le client a changé la quantité commandée
d’un produit ?
Les Déclencheurs (Triggers) DANS PL/SQL
Trigger ligne avec OLD et New (2/4)
Réponse : on tombe dans une incohérence,
il faut donc créer un trigger de mise à jour ( UPDATE) ?

CREATE or replace TRIGGER Ventes_diff


BEFORE UPDATE of qtt_commande ON commandes
REFERENCING NEW as nouv OLD AS enci
FOR EACH ROW
declare
diff number(10) ;
begin
diff:= :nouv.qtt_commande - :enci.qtt_commande ;
UPDATE Stocks SET Stocks.qtt_produit=Stocks.qtt_produit-diff
WHERE Stocks.IDproduit = :nouv.IDproduit ;
end;
Faisons un test ensemble!:
1er test) update commandes set qtt_commande=200 where IDproduit=111
2er test) update commandes set qtt_commande=50 where IDproduit=111
Après voir la table stock
Les Déclencheurs (Triggers) DANS PL/SQL
Trigger ligne avec OLD et New (3/4)
Autre Question à poser Que ce que va se passer si le client a carrément annulé une
laquelle à votre avis ? commande d’un ou plusieurs produit ?
Réponse : Il faut un trigger delete

CREATE or replace TRIGGER Ventes_dell


before delete ON commandes
REFERENCING NEW as nouv OLD AS enci
FOR EACH ROW
begin
UPDATE Stocks SET Stocks.qtt_produit=Stocks.qtt_produit+ :enci.qtt_commande
WHERE Stocks.IDproduit = :enci.IDproduit ;
end;

Faisons un test ensemble!:


delete from commandes where IDproduit=111
Après vérifier les quantités dans la table stock
Les Déclencheurs (Triggers) DANS PL/SQL
Trigger ligne avec OLD et New (4/4)

Une bonne pratique stipule :


« Il ne faut pas créer tout ces trigger que faire ! »
Que faire alors ?

Réponse:

Il faut créer un seul trigger et y rassembler toutes


ces contraintes
Les Déclencheurs (Triggers) DANS PL/SQL
Restriction d'une Trigger ligne: Exemple

CREATE OR REPLACE TRIGGER derive_commission_pct


BEFORE INSERT OR UPDATE OF salary ON employees
FOR EACH ROW
WHEN (NEW.job_id = 'SA_REP')
BEGIN
IF INSERTING THEN :NEW.commission_pct := 0;
ELSIF :OLD.commission_pct IS NULL THEN :NEW.commission_pct := 0;
ELSE :NEW.commission_pct := :OLD.commission_pct+0.05;
END IF;
END;
/
Les Déclencheurs (Triggers) DANS PL/SQL
Implémentation d’un trigger pour respecter une contrainte d’integrité

UPDATE employees SET department_id = 999


WHERE employee_id = 102;
-- Integrity constraint violation error
CREATE OR REPLACE TRIGGER employee_dept_fk_trg
AFTER UPDATE OF department_id
ON employees FOR EACH ROW
BEGIN
INSERT INTO departments VALUES(:new.department_id,
'Dept '||:new.department_id, NULL, NULL);
EXCEPTION
WHEN DUP_VAL_ON_INDEX THEN
NULL; -- masquer l’exception si le department existe déja
END;

UPDATE employees SET department_id = 999 WHERE employee_id = 102


Les Déclencheurs (Triggers) DANS PL/SQL
Le Trigger INSTEAD OF

Application
INSERT INTO ma_view . . .;

INSERT
Trigger de type TABLE1
INSTEAD OF

UPDATE
TABLE2

MA_VIEW
Les Déclencheurs (Triggers) DANS PL/SQL
Exemple de Le Trigger INSTEAD OF
create view nom_emp as select employee_id,last_name,job_id
from employees;

insert into nom_emp values(7878,'LOLO','IT_PROG');

create or replace trigger ins_view_nom_emp


instead of insert on nom_emp
begin
insert into employees
values(:new.employee_id,null, :new.last_name,
'email'||:new.last_name,
null, sysdate, 'IT_PROG', null, null,null,null);
end;
insert into nom_emp values(7878,'LOLO','IT_PROG');
Les Déclencheurs (Triggers) DANS PL/SQL
Comparaison entre TRIGGERS et procédures/fonction stockées

Triggers Procedures/Fonctions
Définit par CREATE TRIGGER Defined with CREATE PROCEDURE
Le dictionnaire de données contient Le dictionnaire de données contient le
le code source dans USER_TRIGGERS. code source dans USER_SOURCE.
Implicitement invoqué explicitement invoqué
Les COMMIT, SAVEPOINT, et COMMIT, SAVEPOINT, et ROLLBACK sont
ROLLBACK ne sont pas autorisés. autorisés
Les Déclencheurs (Triggers) DANS PL/SQL

Gestion des Triggers


– Activer ou désactiver un trigger:

ALTER TRIGGER trigger_name DISABLE | ENABLE

– Activer ou désactiver tout les triggers d’une table:

ALTER TABLE table_name DISABLE | ENABLE ALL TRIGGERS

– Recompiler un triggers d’une table :

ALTER TRIGGER trigger_name COMPILE


Les Déclencheurs (Triggers) DANS PL/SQL

Suppression des Triggers


Pour supprimer un trigger de la base de données database,
on utilise l’instruction DROP TRIGGER

DROP TRIGGER trigger_name;


Exemple

DROP TRIGGER secure_emp;

NB: Tout les triggers d’une table sont supprimés une fois table est
supprimée.

Vous aimerez peut-être aussi