You are on page 1of 120

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)
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 utilisé 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.


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 les exemples de slide suivant ( n oublier pas


celui du commentaire)
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(‘impossible de diviser par 0’);
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 where id_employees =509;

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’inserer
b- enregistrer le code dans le fichier scipt1.sql , donner la commande
d’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


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éclaré implicitement.
END LOOP ;

Le mot clef REVERSE - La boucle FOR du PL/SQL s'incrémente (ou se décrémente)


à l’effet escompté. forcément de 1 en 1.
- On pourra également utiliser un curseur dans la clause IN
Exemple
- Vous pouvez cependant simuler un pas supérieur, comme le
montre cet extrait de la doc :
FOR ii IN REVERSE 1..15
LOOP Exemple
jj:=ii*31;
DECLARE
END LOOP step INTEGER := 2;
BEGIN FOR i IN 1..5
LOOP DBMS_OUTPUT.PUT_LINE (i*step);
END LOOP;
END;

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 son 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 salary INTO sal FROM employees where employee_id=60000;

IF sal > 100000


THEN RAISE sal_nul;
Else
dbms_output.put_line(‘vous pouvez augmenter le salaire de vos employés’);
END IF;
EXCEPTION
WHEN sal_nul THEN
dbms_output.put_line(‘plafond dépassé’);
When zero_divide then
dbms_output.put_line(‘attention ‘);
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_30 is select first_name , salary From employees
where department_id= 30 order by salary;
nom employees .first_name%TYPE;
salaire employees . salary%TYPE;
Begin
Open dept_30;
Loop
Fetch dept_30 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;
Exit when (c1%notfound) ;
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 dernier 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_ 30 is select first_name , salary From employees
where department_id= 30 order by salary;
nom employees .first_name%TYPE;
salaire employees . salary%TYPE;
Begin
Open dept_30;
Fetch dept_30 into nom, salaire;
While dept_30%FOUND Loop
If salaire > 2500 then insert into résultat values (nom,salaire);
end if;
Fetch dept_30 into nom, salaire;
end loop;
close dept_30;
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;
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 ;
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 variables 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 meme question 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 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 prélèvement fiscal de l'employé dont la tax est sup au
max des tax de département 30
SELECT employee_id, first_name,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

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
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
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;
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
 Gérer ( supp. , modif, dé/activation 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 :


« pour les 3 cas que nous venons de voir, Il ne faut
pas créer tout ces triggers»
Que faire alors ?

Réponse:

Il faut créer un seul trigger et qui répond à toutes


ces contraintes
Les Déclencheurs (Triggers) DANS PL/SQL

Avec BEFORE et AFTER on ne peux modifier les valeurs de :OLD. 


Avec BEFORE on peux modifier :NEW 
Avec AFTER on ne peut modifier :NEW.
Exemple :

CREATE OR REPLACE TRIGGER doubler_la_mise


BEFORE INSERT OR UPDATE ON commande
REFERENCING NEW AS nouv
FOR EACH ROW
BEGIN
:nouv.Qtt_commandee:=:nouv.Qtt_commandee *2;
END;

BEFORE : pour autoriser/interdire des traitements (raise_application_error)

AFTER : pour compléter les traitements (n'échouent jamais, pas de


raise_application_error).
Les Déclencheurs (Triggers) DANS PL/SQL
Restriction (Filtre) d'un Trigger ligne

On peut restreindre un traitement sur un enregistrement bien particulier

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
Mutating trigger :
• Si Le trigger traite une table verrouillée ( delete, Update , insert)
– impossible de la modifier ailleurs
• Si nécessité de modifier un autre enregistrement de cette table, alors
rédiger une procédure
Exemple de table en mutatioin
Soit la table MARQUE(#code_M, NOM_Marq, PRIX)
Condition NOM_Marq = { Gold ou BleuH}
Create or replace trigger TR_Marq After INSERT on MARQUE
FOR EACH ROW
BEGIN
IF :new.nom_marq!= ‘Gold' and :new.nom_marq!= ‘BleuH' THEN
Delete from MARQUE where code_M =:new. code_M;
dbms_output.put_line('nom de la Marque est incorrecte');
end if ;
END;
Une fois on insère un nouvelle ligne dans la table marque
le message d’erreur va apparaitre

ORA-04091: table MARQUE en mutation,


déclencheur/fonction ne peut la voir
ORA-06512: à " TR_Marq ", ligne xx
ORA-04088: erreur lors d'exécution du déclencheur ' TR_Marq ‘

La solution dans ce cas est


Create or replace trigger TR_Marq Before INSERT on MARQUE
FOR EACH ROW
BEGIN
BEGIN IF :new.nom_marq!= ‘Gold' and :new.nom_marq!= ‘BleuH' THEN
;RAISE_APPLICATION_ERROR(-20500,'nom de la marque incorrecte')
;END IF
;end
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.

You might also like