Vous êtes sur la page 1sur 111

PL/SQL

INTRODUCTION

• PL/SQL est un langage procédural (Procedural Language/SQL) qui permet en plus de SQL d'avoir les
mécanismes des langages algorithmiques.

• Extension du SQL: des requêtes SQL intégrées avec les structures de contrôle habituelles
(alternatives, répétitives )

• L'unité de programmation PL/SQL est le bloc.

• Un bloc contient des déclaration de variables ou de constantes et des instructions (qui peuvent être
des commandes SQL).

• Des variables peuvent être utilisées pour mémoriser des résultats de requêtes.
INTRODUCTION
• Parmi les instructions d'un bloc PL/SQL on a:
• commandes SQL,
• instructions de boucle (LOOP ),
• instructions conditionnelles (IF-THEN- ELSE ),
• traitement des exceptions,
• appels à d'autres blocs PL/SQL.

• Un programme PL/SQL est composé de fonctions, de procédures, de triggers..


• Les blocs PL/SQL qui définissent des fonctions ou procédures, peuvent être groupés en
packages.
• PL/SQL permet de traiter le résultat d'une requête tuple par tuple.
• La notion de curseur sert à cet effet
ENVIRONNEMENT CLIENT-SERVEUR

• chaque instruction SQL donne lieu à l’envoi d’un message du client vers
le serveur suivi de la réponse du serveur vers le client
• un bloc PL/SQL donne lieu à un seul échange sur le réseau entre le client
et le serveur.
• Les résultats intermédiaires sont traités côté serveur
• seul le résultat final est retourné au client.
AVANTAGES

• La modularité : Un bloc peut être nommé pour devenir une procédure ou une
fonction catalogué, donc réutilisable.

• La portabilité: indépendant du système d’exploitation qui héberge le serveur MySQL.

• L’intégration avec les données des tables : on retrouvera tous les types de données
et d’instructions disponibles sous SQL, des mécanismes pour parcourir des résultats
de requêtes (curseurs), pour traiter des erreurs (handlers) et pour programmer des
transactions (COMMIT, ROLLBACK, SAVEPOINT).
UN BLOC PL/SQL

• Un bloc est l’unité de programmation en PL/SQL

• Un bloc est dit anonyme s’il n’est pas nommée.

• Un bloc a un nom quand il définit une fonction, une procédure ou un package

• Un bloc a:
• Une partie déclarations( optionnelle),

• Une partie instructions,

• Et une partie (optionnelle) de traitement d’exception


PL/SQL - MODES

• Interactif :
• Exécution de code

• Par exemple : contrôler ou corriger des données

• Stocké :
• Procédures, fonctions ou de triggers

• Appel interne :

• Programme :
• Appel depuis langages généralistes (JDBC)
STRUCTURE D’UN BLOC PL/SQL

• Un bloc PL/SQL peut contenir:

– Toute instruction du LMD (SELECT, INSERT, UPDATE, DELETE)

– Les commandes de gestion des transactions ( COMMIT, ROLLBACK,


SAVEPOINT )

• Les sections DECLARE et EXCEPTION sont optionnelles.

• Chaque instruction se termine par ;


STRUCTURE D’UN BLOC PL/SQL
Programme PL/SQL = bloc (procédure anonyme, procédure nommée, fonction
nommée) :
STRUCTURE D’UN BLOC PL/SQL- EXEMPLE
ACCEPT nom_prod prompt 'nom du produit désiré'
DECLARE
qte_stock number(5);
BEGIN
SELECT quantite INTO qte_stock FROM stock
WHERE produit = '&nom_prod';
IF qte_stock > 0 THEN
UPDATE stock SET quantite = quantite -1
WHERE produit = '&nom_prod’;
INSERT INTO VENTES VALUES (&nom_prod || 'VENDU');
ELSE
INSERT INTO VENTES VALUES (&nom_prod ||'DEMANDE DE REASTOCK');
END IF;
COMMIT;
END;
RÈGLES SYNTAXIQUES D'UN BLOC PL/SQL

Identifiants :

• Peuvent contenir jusqu’à 30 caractères.

• Ne peuvent pas contenir de mots réservés à moins qu'ils soient encadrés de


guillemets.

• Doivent commencer par une lettre.

• Doivent avoir un nom distinct de celui d'une table de la base ou d'une colonne.
RÈGLES SYNTAXIQUES D'UN BLOC PL/SQL

• Utiliser un slash (/) pour exécuter un boc PL/SQL anonyme dans PL/SQL.
• Placer un point virgule (;) à la fin d’une instruction SQL ou SQL*PLUS
• Les chaînes de caractères et les dates doivent être entourées de simples quottes ( '
' ).
• Les commentaires peuvent être
- sur plusieurs lignes avec :
/* début et
fin de commentaire*/
- sur une ligne précédée de :
-- début et fin de commentaire
IMBRICATION DES BLOCKS PL/SQL
Un bloc peut être imbriqué dans un autre bloc

Portée d’un identificateur :


• un descendant peut accéder aux identificateurs déclarés par un parent, pas l’inverse
• Si une variable est déclarée dans un premier bloc et aussi dans un sous bloc, la variable
du bloc supérieur n’est plus visible dans le sous-bloc.
LES VARIABLES
VARIABLES
• Toute variable PL/SQL :
• Obligatoirement défini dans DECLARE avant utilisation
• Types de variables PL/SQL :
• Types Scalaires (recevant une seule valeur d’un type SQL) :
• NUMBER(5,2),
• VARCHAR2,
• DATE,
• BOOLEAN, ..
• Composites
• %TYPE (schéma d’un attribut),
• %ROWTYPE (schéma d’une table ou résultat de requête),
• TABLE (tables dynamiques),
VARIABLES
• Types de variables PL/SQL :
• Types Scalaires (recevant une seule valeur d’un type SQL) :
• NUMBER(5,2),
• VARCHAR2,
• DATE,
• BOOLEAN, ..
• Composites
• %TYPE (schéma d’un attribut),
• %ROWTYPE (schéma d’une table ou résultat de requête),
• TABLE (tables dynamiques),
VARIABLES SCALAIRES
• Types Scalaires (Oracle) : NUMBER(5,2), VARCHAR2, DATE, BOOLEAN, ...
• Syntaxe de déclaration :
Identificateur [CONSTANT] type [[NOT NULL] {:= | DEFAULT}
expression];
CONSTANT : si c’est une constante elle doit être initialisée
NOT NULL : on ne peut pas lui affecter une valeur nulle (sinon exception VALUE_ERROR)
Initialisation : := (affectation) / DEFAULT
Pas de déclaration multiple dans PL/SQL :

Il ne faut pas écrire : number1, number2 NUMBER; ← déclaration incorrecte !!


Il faut écrire : number1 NUMBER ; number2 NUMBER ; ← déclaration Correcte !!
VARIABLES SCALAIRES - EXEMPLES

DECLARE
pi CONSTANT FLOAT := 3.14159;
nom varchar2 (10) NOT NULL;
rayon FLOAT DEFAULT 1;
adresse varchar2 (20);
x INT := 1;
date_cmd date := sysdate+7;
surface DOUBLE := pi * rayon ** 2;
valide BOOLEAN NOT NULL := TRUE;
INITIALISATION DES VARIABLES
• Possibilité d’affecter une valeur grâce à une requête SQL !
• Exemple :
/* la variable est var_id_avion et elle sera initialisée par id_avion du id_vol=3 */
SELECT id_avion INTO var_id_avion FROM AVION
WHERE id_vol = 3;

• Si le SELECT retourne 1 ligne c’est OK


• Si le SELECT retourne 0 ligne : « NO_DATA_FOUND » erreur PL/SQL générée
• Si le SELECT retourne plusieurs lignes : « TOO_MANY_ROWS » erreur PL/SQL générée
VARIABLES
• Types de variables PL/SQL :
• Types Scalaires (recevant une seule valeur d’un type SQL) :
• NUMBER(5,2),
• VARCHAR2,
• DATE,
• BOOLEAN, ..
• Composites
• %TYPE (schéma d’un attribut),
• %ROWTYPE (schéma d’une table ou résultat de requête),
• TABLE (tables dynamiques),
VARIABLES COMPOSITE - %type

• Variables composites : %TYPE


• Déclarer une variable par référence à:
• Le type d’un attribut( colonne) d’une table ou d’une vue existance
• Une autre variable déclarée
• Exemple :
VARIABLES COMPOSITE - %ROWTYPE

• Variables composites : %ROWTYPE


• Permet de travailler au niveau d'un enregistrement. Ce dernier est composé d'un
ensemble de colonnes. L'enregistrement peut contenir toutes les colonnes d'une
table ou seulement certaines.
• Contraintes NOT NULL de la table sont non transmises
• Exemple :
VARIABLES COMPOSITE – %ROWTYPE
DECLARE
R_AVION avion%ROWTYPE; -- basé sur la structure d'une ligne de la table
avion;
BEGIN
SELECT * INTO R_AVION FROM avion WHERE Id_avion=3;

-- afficher les données


DBMS_OUTPUT.PUT_LINE('ID : '|| r_avion.ID_avion);
DBMS_OUTPUT.PUT_LINE('Modeles : '|| r_avion.Modele);
DBMS_OUTPUT.PUT_LINE('capacité : '|| r_avion.capacite);
End;
VARIABLES COMPOSITE - exercice

Soit le Schéma suivant :


FILM (IDFILM, TITRE, #IDMESC, ANNEE, COUT, RECETTE)
ARTISTE (ID, NOM, PRENOM, DATENAISS)
• Créer une procédure anonyme qui permet
• Pour un id de Film donné :
- Récupère le titre du film correspondant,
- Récupère les information du metteur en scène (id_mesc) dans la
table Artiste
- Affiche le titre et le nom à l’aide de DBMS_OUPUT.PUT_LINE
( c’est l’équivalent de SYSTEM.OUT.PRINTLN en java)
VARIABLES COMPOSITE - Corrigé
Film (idfilm, titre, #idMes, annee, cout, recette)
Set SERVEROUTPUT on Artiste (id, nom, prenom, date_naiss)
DECLARE
T_TITRE Film.titre%TYPE; --variable v_titre et v_idmes du même type de titre et idmes dans table Film
T_IDMES Film.idMESC%TYPE;
R_MESC Artiste%ROWTYPE; --variable v_mesc du même type d’une ligne dans table Artise
mon_id_Film number(3) := 4 -
BEGIN
-- Recherche du film
SELECT titre, idMES INTO T_TITRE, T_IDMES
FROM Film
WHERE idFilm = mon_id_Film;
-- Recherche du metteur en scène
SELECT * INTO R_MES
FROM Artiste
WHERE id = T_IDMES;
-- Affichage du résultat
DBMS_OUPUT.PUT_LINE (T_TITRE || ', est réalisé par ' || R_MESC.PRENOM || ' ' || R_MESC.NOM);
VARIABLES COMPOSITE - RECORD
• Les records sont des variables composites qui peuvent stocker des valeurs de données de
différents types
• PL/SQL peut gérer les types de records suivants :
- Basés sur une table/vue/curseur ou définis par l'utilisateur.
Syntaxe (basé sur une table /vue/curseur):
NOM_RECORD NOM_TABLE%ROWTYPE;
Syntaxe (défini par l’utilisateur):
TYPE nom_record IS RECORD (
champ1 typedonnees1 [NOT NULL] [:= expression_par_defaut],
champ2 typedonnees2 [NOT NULL] [:= expression_par_defaut],
...
champN typedonneesN [NOT NULL] [:= expression_par_defaut);
);
VARIABLES COMPOSITE - TABLE

• Tableaux dynamiques , composé de :


• Clé primaire
• Colonnes de type scalaire
• % TYPE , %ROWTYPE, record
• Fonction PL/SQL dédiées aux tableaux:
• EXISTS(x), PRIOR(x), NEXT (X), DELETE(X,…)
• COUNT, FIRST, LAST,DELETE
VARIABLES COMPOSITE - TABLE

Quelques fonction pour les tableaux :


• EXISTS(x) : Retourne TRUE si le Xème élément du tableau existe.

• COUNT : Retourne le nombre d’éléments du tableau.

• FIRST/LAST : Retourne le premier/dernier indice du tableau (NULL si vide).

• PRIOR(x)/NEXT(x) :Retourne d’éléments avant/après le Xème élément du tableau.

• DELETE/DELETE(x)/DELETE(x,y) : Supprime un ou plusieurs éléments du tableau.


VARIABLES COMPOSITE – TABLE - Exemple
DECLARE
TYPE avion_typetab IS TABLE OF avion%ROWTYPE INDEX BY BINARY_INTEGER;
TYPE x_typetab IS TABLE OF VARCHAR(6) INDEX BY BINARY_INTEGER;
T1 Table_avion;
X1 x_typetab;
nb BINARY_INTEGER;
Begin
X1(1) :='X01’;
X1(2) :='X02’;
X1(3214) :='X3214’;
nb :=T1.count;
T1(1).Id_avion := 1;
T1(1).modele := 'BOEING737’;
T1(1).capacite := 186;
T1.delete(1);
end;
AFFECTATION DE : LIGNE DE COMMANDE

• Il est possible de passer en paramètres d'entrée d'un bloc PL/SQL des


variables définies sous SQL*PLUS.
• On accède aux valeurs d'une telle variable dans le code PL/SQL en faisant
préfixer le nom de la variable par un « & ».
• La directive ACCEPT permet de faire une lecture de la variable au clavier.
AFFECTATION DE : LIGNE DE COMMANDE
ACCEPT v_modele PROMPT 'Entrez le modèle avion:’;

ACCEPT v_capacite PROMPT 'Veuillez saisir la capacité avion:';

DECLARE
idavion avion.id_avion%type default 100;
BEGIN
INSERT INTO avion(id_avion, modele, capacite )
VALUES(idavion, '&v_modele',&v_capacit);
INSERT INTO avion (id_avion, modele, capacite)
VALUES(&idavion , '&modele', &capacite);
END;
/
Opérateurs en PL/SQL

• Logiques: AND , OR, NOT

• Arithmétique: + - * / mod ** (exponentielle)

• Comparaison: =, >, !=, >, <=, >=, IS NULL, LIKE, BETWEEN

• Concaténation: ||

• Parenthèses pour contrôler l'ordre des opérations ()

• Affectation: :=
AFFICHAGE

• Paquetage DBMS_OUTPUT : Pour afficher le contenu d’une variable


• Affichage d’une valeur :
PUT(valeur IN {VARCHAR2 | DATE | NUMBER});
• Affichage d’une valeur suivie de fin de ligne :

PUT_LINE(valeur IN {VARCHAR2 | DATE | NUMBER});

• Par défaut, les fonctions d’affichage sont désactivées.


• À activer avec SET SERVEROUTPUT ON
EXERCICES
Ecrire un bloc PL/SQL qui permet d’affecter aux variables A et B des valeurs, puis permuter
les valeurs de ces deux variables.
SET SERVEROUTPUT ON;
ACCEPT A PROMPT 'ENTRER LA VALEUR DE A : ';
ACCEPT B PROMPT 'ENTRER LA VALEUR DE B : ‘;
DECLARE
TEMP NUMBER(5) ;
A1 NUMBER(5) := '&A';
B1 NUMBER(5) := '&B';
BEGIN
TEMP :=A1;
A1 := B1;
B1 :=TEMP;
DBMS_OUTPUT.PUT_LINE ('A = ' || A1 || ' ET B = ' || B1 );
END;
/
STRUCTURES DE CONTRÔLE

• Les branchements Conditionnels


• IF THEN ELSE

• CASE WHEN

• Structures Répétitives
• WHILE

• LOOP

• FOR
STRUCTURES CONDITIONNELLES

IF <condition> THEN
<instructions> ;
ELSIF <condition> THEN
<instructions> ;
ELSE
<instructions> ;
END IF;
STRUCTURES CONDITIONNELLES - IF -
Exemple
DECLARE
nb_passager avion.capacite%TYPE;
BEGIN
SELECT capacite INTO nb_passager FROM avion WHERE modele= 'A319' ;
IF nb_passager > 600 THEN
DBMS_OUTPUT.PUT_LINE('c''est un gros avion');
ELSIF nb_passager <=150 THEN
DBMS_OUTPUT.PUT_LINE('c''est un petit avion');
ELSE
DBMS_OUTPUT.PUT_LINE('c''est un moyen avion');
END IF;
END;
/
STRUCTURES CONDITIONNELLES

CASE <variable>
WHEN <value > THEN
<instructions> ;

WHEN <value > THEN
<instructions> ;
ELSE
<instructions> ;
END CASE;
STRUCTURES CONDITIONNELLES - CASE –
Exemple1
DECLARE
v_mention CHAR(2);
v_note DECIMAL(4,2) DEFAULT 13;
BEGIN
v_note := &note;
Case
WHEN v_note >=16 THEN v_mention := 'TB';
WHEN v_note >=14 THEN v_mention := 'B';
WHEN v_note >=12 THEN v_mention:= 'AB';
WHEN v_note >=10 THEN v_mention := 'P';
ELSE v_mention := 'R';
END CASE;
DBMS_OUTPUT.PUT_LINE('votre mention est ' || v_mention );
END;
STRUCTURES CONDITIONNELLES - CASE -Exemple
2
DECLARE
v_mention CHAR(2);
v_note DECIMAL(4,2) DEFAULT 13;
BEGIN
v_note := &note;
Case v_note
WHEN 16 THEN v_mention := 'TB';
WHEN 14 THEN v_mention := 'B';
WHEN 12 THEN v_mention:= 'AB';
WHEN 10 THEN v_mention := 'P';
ELSE v_mention := 'R';
END CASE;
DBMS_OUTPUT.PUT_LINE('votre mention est ' || v_mention );
END;
STRUCTURES REPETITIVES- WHILE - EXEMPLE
WHILE <condition> LOOP
<instructions> ;
END LOOP;

DECLARE
a INTEGER := 1;
b INTEGER := 1;
BEGIN
WHILE b <= 10 LOOP
DBMS_output.put('a= ' || a || '*' || b);
a := a * b;
b := b + 1;
DBMS_output.put_line(' = ' ||a );
END LOOP;
END;
/
STRUCTURES REPETITIVES – LOOP – EXEMPLE
LOOP
<instructions> ;
EXIT WHEN <condition> ;
<instructions>
END LOOP;
DECLARE
a INTEGER := 1;
b INTEGER := 1;
BEGIN
LOOP
DBMS_output.put('a= ' || a || '*' || b);
a := a * b;
b := b + 1;
DBMS_output.put_line(' = ' ||a );
EXIT WHEN b > 10 ;
END LOOP;
END;
/
STRUCTURES REPETITIVES – FOR – EXEMPLE
FOR <variable> IN <value> .. <value> LOOP
<instructions> ;
END LOOP;

DECLARE
a INTEGER := 1;
b INTEGER := 1;
BEGIN
FOR i in 1..10 LOOP
DBMS_output.put('a= ' || a || '*' || b);
a := a * b;
b := b + 1;
DBMS_output.put_line(' = ' ||a );
END LOOP;
END;
/
EXERCICES

1. Ecrire un bloc PL/SQL qui permet d’initier une variable a, puis calculer le factorielle de a.
2. Ecrire un bloc PL/SQL qui permet de calculer le produit et la somme des nombres entre 100 et 200.
3. Ecrire un bloc PL/SQL qui calcule le reste de la division de deux nombres sans utiliser la fonction MOD
4. Créer un type tableau pouvant contenir jusqu’à 20 entiers.
a. Créer une variable de ce type, faites une allocation dynamique et dimensionner ce tableau à 5
lignes.
b. remplir ce tableau avec la liste des 5 premiers carrés parfaits : 1, 4, 9, 16, 25
c. Affichez ce tableau.
EXERCICES
Ecrire un bloc PL/SQL qui permet d’initier une variable a, puis calculer le
factorielle de a.
DECLARE
v_a number(10) := 10;
v_F number(10) :=1 ;
BEGIN
dbms_output.put(v_a);
LOOP
v_F := v_F * v_a;
v_a := v_a -1;
exit when v_a =1;
END LOOP;
dbms_output.put_line ('!= ' || v_F );
END;
EXERCICES

Ecrire un bloc PL/SQL qui permet de calculer le produit et la somme des nombres entre
100 et 200.
DECLARE
PRODUIT NUMBER := 1 ;
SOMME NUMBER := 0;
BEGIN
FOR i IN 100..200 LOOP
produit = produit * i ;
somme = somme + i ;
END LOOP
DBMS_OUTPUT.PUT_LINE('Somme = ' || somme) ;
DBMS_OUTPUT.PUT_LINE(Produit = ' || produit) ;
END;
EXERCICES
Ecrire un bloc PL/SQL qui calcule le reste de la division de deux nombres sans utiliser la fonction MOD
DECLARE
nb1 number(5) := '&a’ ;
nb2 number(5) := '&b’ ;
reste NUMBER := nb1;
BEGIN
IF nb1>nb2 THEN
WHILE reste > nb2 LOOP
reste := reste – nb2;
END LOOP
DBMS_OUTPUT.PUT_LINE('Le reste de ' || nb1 || ' par ' || nb2 || ' est : ' || reste);
ELSIF nb1<nb2 THEN
WHILE reste > nb1 LOOP
reste := reste – nb1;
END LOOP ;
DBMS_OUTPUT.PUT_LINE ('Le reste de ' || nb2 || ' par ' || nb1 || ' est : ' || reste);
ELSE
DBMS_OUTPUT.PUT_LINE ('Le reste de ' || nb2 || ' par ' || nb1 || ' est : ' || 0);
END IF;
END;
EXERCICES
Créer un type tableau pouvant contenir jusqu’à 20 entiers.
a. Créer une variable de ce type, faites une allocation dynamique et dimensionner ce tableau à 5 lignes.
b. remplir ce tableau avec la liste des 5 premiers carrés parfaits : 1, 4, 9, 16, 25
c. Affichez ce tableau.
DECLARE
TYPE tab1 IS TABLE OF integer; --créer le type tab1
t tab1 ; --créer une variable de ce type
BEGIN
t := tab1();
t.extend(5); --dimensionner le tableau à 5 ligne
FOR i IN 1..5 LOOP
t(i) := i*i; --remplir ce tableau avec la liste des 5 premiers carrés parfaits : 1, 4,
9, 16, 25
END LOOP ;
FOR i IN 1..5 LOOP
DBMS_OUTPUT.PUT_LINE('t(' || i||')='||t(i)); -- afficher tableau
END LOOP ;
EXERCICES
Créer un type tableau pouvant contenir jusqu’à 20 entiers.
a. Créer une variable de ce type, faites une allocation dynamique et dimensionner ce tableau à 5 lignes.
b. remplir ce tableau avec la liste des 5 premiers carrés parfaits : 1, 4, 9, 16, 25
c. Affichez ce tableau.
DECLARE
TYPE tab1 IS TABLE OF integer; --créer le type tab1
t tab1 ; --créer une variable de ce type
i number
BEGIN
t := tab1();
t.extend(5);
i :=t.first
WHILE i IS NOT NULL LOOP
t(i) := i*i; --remplir ce tableau avec la liste des 5 premiers carrés parfaits : 1, 4,
9, 16, 25
DBMS_OUTPUT.PUT_LINE('t(' || i||')='||t(i)); -- afficher tableau
i:=t.next(i);
END LOOP ;
LES CURSEURS
• Le mot CURSOR sert à déclarer une zone mémoire qui recevra le
résultat d’un select pour un parcours tuple par tuple

DECLARE
CURSOR VolCursor IS SELCET id_vol, arrivee, depart
FROM VOL WHERE depart=‘CGD’ ;
Utilisation d’un curseur explicite

NON

OUI
DECLARE OPEN FETCH VIDE? CLOSE

• Définition d’un • Ouverture du • Parcourir les • Tester • Fermeture du


curseur curseur tuples l’existence / curseur
• Créer une • Allouer la zone • Charger la l’inexistence • Libérer l’espace
zone mémoire mémoire ligne en cours des lignes mémoire alloué
SQL • Exécution de dans des
la requête variables
Curseurs : instructions – exemple 1
DECLARE
-- étape 1 : creation/définition d’un curseur sur lesvols
CURSOR LesVols IS SELECT * FROM vol;
-- Variable d’affectation des tuples
UnVol vol%ROWTYPE;
BEGIN
-- étape 2: Ouverture du curseur et exécution de la requête
OPEN LesVols;
-- étape 3: Chargement d’un tuple, et positionnement sur le suivant
FETCH LesVols INTO UnVol;
/* Traitement */
-- étape 4: Fermeture du curseur et libération mémoire
CLOSE LesVols;
END;
Curseurs : instructions – exemple 2
DECLARE
CURSOR LicenceINFO IS
SELECT nomEtu , note FROM NoteExam
WHERE specialite=‘informatique’ order by note;

v_nomEtu NoteExam.nomEtu %TYPE;


v_note NoteExam.note %TYPE;
BEGIN
OPEN LicenceINFO;
LOOP
FETCH LicenceINFO INTO v_nomEtu, v_note;
EXIT WHEN LicenceINFO%NOTFOUND;
IF (v_note >=10) THEN
dbms_output.put_line(v_nometu ||’ a validé le module’);
END IF;
END LOOP;
CLOSE LicenceINFO;
END;
Curseurs explicites : attributs

• nomCurseur%ISOPEN
ÞTRUE si le curseur est ouvert
• nomCurseur%FOUND
ÞTRUE si le dernier FETCH contient un tuple
• nomCurseur%NOTFOUND
ÞTRUE si le dernier FETCH ne contient pas de tuples
• nomCurseur%ROWCOUNT
Þnombre total de lignes traitées jusqu’à présent
Curseur : Exercice1

Créer un programme avec curseur qui permet de :


• Afficher pour chaque utilisateurs ORACLE commençant par la lettre ‘S’ son
identifiant et son nom
• Calculer le nombre de ces utilisateurs
Corrigé
DECLARE
CURSOR USER_CURS IS
SELECT user_ID, username FROM dba_users WHERE username like 'S%';

v_ID dba_users.user_id%TYPE;
v_NAME dba_users.username%TYPE;
BEGIN
IF ( NOT (USER_CURS%ISOPEN )) THEN
OPEN USER_CURS;
END IF;
LOOP
FETCH USER_CURS INTO v_ID, v_NAME;
EXIT WHEN USER_CURS%NOTFOUND;
DBMS_OUTPUT.PUT_LINE( 'ID utilisateur: ' || v_ID || ' NOM utilisateur : ' || v_NAME );
END LOOP;
DBMS_OUTPUT.PUT_LINE(USER_CURS%ROWCOUNT);
CLOSE USER_CURS;
END;
Curseur : Exercice2

Créer un programme avec curseur


• Récupérer tous les avions dont le départ ou l’arrivé est ‘CDG’
• Afficher pour chaque avion le modèle et la capacité
Corrigé
DECLARE
CURSOR AvionVOL IS
SELECT * FROM avion WHERE
id_avion =( SELECT avion FROM vol WHERE
depart=‘CDG’ or arrivee=‘CDG’) ;
v_avionVol avion%ROWTYPE;
BEGIN
IF ( NOT (AvionVOL%ISOPEN )) THEN
OPEN AvionVOL;
END IF;
LOOP
FETCH AvionVOL INTO v_avionVol ;
EXIT WHEN AvionVOL %NOTFOUND;
DBMS_OUTPUT.PUT_LINE(‘Modele Avion’ || v_avionVol.modele || ‘capacité‘ || v_avionVol.
capacite );
END LOOP;
DBMS_OUTPUT.PUT_LINE(AvionVOL%ROWCOUNT);
CLOSE AvionVOL;
Curseur paramétré

• Objectif : Réutiliser un même curseur avec des valeurs


différentes dans un même bloc PL/SQL
• Syntaxe:
DECLARE
CURSOR non_curseur( param1 type, param2 type, ….) IS
requêtes;
BEGIN
OPEN non_curseur(val1, val2, ..);
FETCH non_curseur into …
CLOSE non_curseur; --( avant d’utiliser d’autre paramètres )
END;
Curseur paramétré – exercice
Créer un programme avec curseur paramétré qui permet de :
• Afficher pour chaque utilisateurs ORACLE commençant par un caractère ’X en
paramètre’ l’identifiant et le nom
• Calculer le nombre de ces utilisateurs
DECLARE
CURSOR USER_CURS (c char) IS SELECT user_ID, username FROM dba_users where username like
c||'%' ;
v_ID dba_users.user_id%TYPE;
v_NAME dba_users.username%TYPE;
BEGIN
OPEN USER_CURS('S');
LOOP
FETCH USER_CURS INTO v_ID, v_NAME;
EXIT WHEN USER_CURS%NOTFOUND;
DBMS_OUTPUT.PUT_LINE( 'ID utilisateur: ' || v_ID || ' NOM utilisateur : ' || v_NAME );
END LOOP;
DBMS_OUTPUT.PUT_LINE(USER_CURS%ROWCOUNT);
CLOSE USER_CURS;
Curseur – la clause CURRENT OF
• OBJECTIF : Accéder directement en modification ou en suppression à la ligne ramenée par Fetch
• Il faut verrouiller les lignes lors de la déclaration du curseur ( FOR UPDATE OF NOM_col)
DECLARE
CURSOR films(idMES Film.ID_MES%TYPE) IS
SELECT * FROM Film WHERE ID_MES = idMES
FOR UPDATE OF recette;
lefilm film%ROWTYPE;
BEGIN
OPEN films(5);
LOOP
FETCH films INTO lefilm;
EXIT WHEN films%notfound;
IF (lefilm.cout - lefilm.recette) > 1000 THEN
UPDATE film set recette =recette*1.3 WHERE CURRENT OF films;
END IF;
END LOOP;
CLOSE films;
END;
Curseur – la clause CURRENT OF
• OBJECTIF : Accéder directement en modification ou en suppression à la ligne ramenée par Fetch
• Il faut verrouiller les lignes lors de la déclaration du curseur ( FOR UPDATE OF NOM_col)

DECLARE
CURSOR films(idMES Film.ID_MES%TYPE) IS
SELECT recette, cout FROM Film WHERE ID_MES = idMES
FOR UPDATE OF recette;
lefilm film%rowtype;
BEGIN
FOR lefilm IN films(1) LOOP
IF (lefilm.cout - lefilm.recette) > 10000 THEN
UPDATE film set recette =recette*1.3 WHERE CURRENT OF films;
END IF;
END LOOP;
END;
GESTION DES EXCEPTIONS
LES EXCEPTIONS

• Une exception : Une erreur ou un événement d'avertissement rencontré


au moment de l'exécution du programme PL/SQL.
• PL/SQL dispose de mécanismes pour gérer ces conditions
exceptionnelles à l'aide du bloc de code EXCEPTION où il est défini
comment contrer la condition d'erreur.
• Les erreurs sont deux types:
• Les erreurs définies par le système (détectées par le moteur PL/SQL).
• Les erreurs définies par l’utilisateur.
LES EXCEPTIONS – deux types
Exceptions définies par ORACLE
• Ex: NO_DATA_FOUND, TOO_MANY_ROWS, STORAGE_ERROR, ZERO_DIVIDE ....
• Se déclenchent automatiquement.
• Prise en compte de l’erreur dans la section EXCEPTION / ou pas .
• Nommées par oracle

Exceptions définies par l’utilisateur


• Déclarées dans un package, un sous-programme ou dans la section déclaration du bloc
PL/SQL
• Nommées par l’utilisateur.
• Interruption de l’exécution du bloc.
• Déclenchées explicitement par le mot clé : RAISE.
• Prise en compte de l’erreur dans la section EXCEPTION
LES EXCEPTIONS - syntaxe
BEGIN
...
EXCEPTION
WHEN nomException1 [OR nomException2 ...] THEN
instructions1;
WHEN nomException3 [OR nomException4 ...] THEN
instructions3;
WHEN OTHERS THEN
instructionsAttrapeTout;
END;
• WHEN : Identifie une ou plusieurs exceptions
• WHEN OTHERS : Indique le traitement à effectuer si l’exception ne peut être
appréhendée par une des clauses WHEN
LES EXCEPTIONS - définies par Oracle

Liste non exhaustive des exceptions prédéfinies:

• CURSOR_ALREADY_OPEN : tentative d’ouverture d’un curseur déjà ouvert


• LOGIN DENIED : connexion échouée
• NO_DTA_FOUND: la commande SELECT INTO ne retourne aucune valeur
• PROGRAM_ERROR : problème général du au pl/SQL
• TOO_MANY_ROWS : la commande SELECT INTO retourne plus d’une ligne
• ZERO_DIVIDE : tentative de division par zéro
LES EXCEPTIONS - définies par Oracle
LES EXCEPTIONS PRÉDÉFINIES – exemple 1
Accept var prompt ‘ chercher le vol numero ‘
DECLARE
v_vol vol%rowtype;
BEGIN
Select * into v_vol from vol where id_vol=&var
DBMS_OUTPUT.PUT_LINE(‘ depart: ‘|| v_vol.depart || ‘ arrivée ‘|| v_vol.arrivée )
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('Pas de détail trouvé sur le vol numéro'||
&var );
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('ERREUR’);
END;
LES EXCEPTIONS : définies par l'utilisateur

• Les développeurs peuvent créer leurs propres exceptions, les utiliser


pour gérer les erreurs.
• Les exceptions peuvent être créés dans la partie déclaration d'un sous-
programme
• ne sont accessibles qu'à l'intérieur de ce sous-programme
• Nous pouvons lever à la fois des exceptions définies par l'utilisateur
et/ou définies par le système.
• Les règles de visibilité des exceptions sont les mêmes que celles des
variables.
LES EXCEPTIONS : définies par l'utilisateur
DECLARE
Erreur2 EXCEPTION;
BEGIN
FOR i IN (SELECT * FROM avion) LOOP
DBMS_OUTPUT.PUT_LINE('i.ID_AVION'|| i.ID_AVION );
IF i.ID_AVION=4 THEN RAISE Erreur2;
END IF;
END LOOP;
EXCEPTION
WHEN Erreur2 THEN
DBMS_OUTPUT.PUT_LINE('l''avion numéro 4 existe déjà dans la table');
END;
LES EXCEPTIONS : définies par l'utilisateur
DECLARE
nb integer := 0;
BEGIN
select count(avion) into nb from vol where avion=1 group by avion;
IF nb > 2
THEN
RAISE_application_error(-20001,'il faut faire une visite de
maintenance');
END IF;

END;
Lors d’une EXCEPTION
• Aucun traitement n’est prévu : le programme s’arrête
• Un traitement est prévu:
1. Arrêt de l’exécution du bloc PL/SQL courant
2. L’exception est recherchée dans la section EXCEPTION
i. Associée au bloc courant,
Sinon dans les blocs parents
Sinon le programme appelant
3. Exception traitée suivant les instructions trouvées
i. Spécifiques
Exécution du traitement prévu par l’exception (THEN...)
ii. Attrape-tout (when others)
LES SOUS PROGRAMMES
INTRODUCTION

• PL/SQL permet l’imbrication de blocs, mais cette pratique n’est pas


recommandée :
• Réduit la lisibilité du code et rend plus difficile sa maintenance
• Les blocs emboités ne peuvent pas être appelés
• Les sous programmes
• PL/SQL offre la possibilité d’utiliser des sous programmes
• Un sous programme PL/SQL est un bloc nommé défini dans la section DECLARE et
pouvant posséder des paramètres
• Il est réutilisable et facilite la maintenance des applications
• Il sécurise les données (gestion des droits/contraintes sur données)
PROGRAMME ET SOUS PROGRAMME

• Nommage et paramétrage de Blocs


• Procédure
• Eventuellement retourne DES résultats
• Fonction
• Résultat unique obligatoire
• Appel possible dans une requêtes SQL
APPEL DE PROGRAMME

• Appel de procédure/fonction depuis un bloc PL/SQL :


nomProcedure(liste_Par_Effectifs);
• Appel de procédure stockée sous SQL*Plus :
SQL> EXECUTE nomProcedure(liste_Par_Effectifs);
• Appel de fonction stockée sous SQL*Plus :
SQL> nomFonction(liste_Par_Effectifs);
PROCÉDURE - SYNTAXE
PROCÉDURE SANS PARAMÈTRES - EXEMPLE
DECLARE
PROCEDURE RECORD_Trace
As
BEGIN
--Enregistrer l’utilisateur courant et la date système dans la table Tab_Trace
INSERT INTO Tab_Trace(User_Uid, User_Name, User_Trace_Date)
VALUES (UID, USER, SYSDATE);
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE (‘ERREUR DÉCLENCHÉE’’ );
END RECORD_Trace;
-- autres déclarations
BEGIN
RECORD_Trace; -- appel procédure
END;
TYPES DE PARAMÈTRES
• IN : Entrée
- Utilisé par défaut
- Une variable accessible en lecture seule: Valeur constante (pas d’affectation)
- Transmis par référence
- Transmettre la valeur de variable dans la procédure
- Utilisé dans des expressions afin de faciliter le calcul d'une valeur
• OUT: Sortie
- Une variable accessible en écriture seulement
- Transmis par valeur
- Attribuer une valeur au paramètre
- Impossible de le lire à partir du corps de la procédure
- Utiles pour transmettre des valeurs calculées à l'intérieur d'une procédure.
• IN OUT : Entrée et sortie
- Accessible en lecture et en écriture
- Transmis par valeur
- Utile pour les variables à modifier à l'intérieur de la procédure et sortir de la procédure
TYPES DE PARAMÈTRES : IN - exemple
DECLARE
PROCEDURE P1(IDA IN avion.ID_AVION%type)
AS
BEGIN
UPDATE avion
SET capacit = capacit + 100 WHERE ID_AVION = IDA
;
END P1;

DECLARE
var1 avion.capacit%type;
v_id avion.ID_AVION%type := 3;
BEGIN
select capacit into var1 from avion where ID_AVION = v_id;
dbms_output.put_line('Avant : la capacité = ' || var1);
P1(v_id);
select capacit into var1 from avion where ID_AVION = v_id;
dbms_output.put_line('Apres : la capacité = ' || var1);
END;
TYPES DE PARAMÈTRES : OUT - exemple
create or replace
PROCEDURE P2(P_ID IN avion.ID_AVION%type, P_mod OUT avion.modele%type,
P_cap OUT avion.capacit%type)
IS
BEGIN
SELECT MODELE, CAPACIT into P_mod, P_cap from avion where
ID_AVION=P_ID;
END P2;

DECLARE
val1 avion.ID_AVION%type :=10 ;
val2 avion.modele%type := 'A444';
val3 avion.capacit%type := 2444;
BEGIN
dbms_output.put_line('AVANT : id= '||val1||' mod= '||val2||' cap= '||val3);
P2(val1, val2, val3);
dbms_output.put_line('Apres : id= '||val1||' mod= '||val2||' cap= '||val3);
END;
PROCÉDURE AVEC PARAMÈTRES - EXEMPLE
DECLARE
PROCEDURE AUGMENTE_SAL(P_EMPNO EMP.EMPNO%TYPE, P_Montant NUMBER)
IS
BEGIN
UPDATE EMP SET SAL = SAL + P_Montant
WHERE NumEMP = P_NumEMP AND P_NumEMP NOT NULL;
IF SQL%NOTFOUND THEN
DBMS_OUTPUT.PUT_LINE (‘MAJ non Effectuée’);
ELSE
DBMS_OUTPUT.PUT_LINE (‘MAJ Effectuée’);
END IF
END AUGMENTE_SAL;
-- autres déclarations
BEGIN
AUGMENTE_SAL(1234, 1000); -- appel procédure
END;
DECLARE
PROCEDURE lesFilms(prenomParam artiste.prenom%type , nomParam artiste.nom%type)
IS
CURSOR films(lePrenom VARCHAR2(20), leNom VARCHAR2(20)) IS
SELECT * FROM Film WHERE id_MES = (
SELECT id FROM Artiste WHERE Nom=leNom and Prenom=lePrenom);
leFilm Film%ROWTYPE;
BEGIN
DBMS_OUTPUT.PUT_LINE(‘le MES : '|| prenomParam ||' '||nomParam );
FOR leFilm IN films(prenomParam,nomParam) LOOP
DBMS_OUTPUT.PUT_LINE(' '||leFilm.titre|| ':'||leFilm.année);
END LOOP;
END lesFilms;
BEGIN
lesFilms(‘prenom1’,‘nom’);
END;
FONCTION - SYNTAXE
FONCTION : EXEMPLE
DECLARE
V_GainFilm NUMBER (10,3);
FUNCTION Gain_film(idf_param IN FILM.IDF%TYPE) RETURN NUMBER
IS
v_gain number;
BEGIN
SELECT recette - cout INTO v_gain FROM film
WHERE idf = idf_param;
RETURN v_gain ;
END Gain_film;

BEGIN
V_GainFilm := Gain_film(IDFILM);
DBMS_OUTPUT.PUT_LINE ('le gain : '|| V_GainFilm );
END;
EXERCICES

Créer des sous programme qui permet de :


• Calculer l'âge d’un artiste donné ,
• Calculer l’âge actuel pour chaque MES
• Calculer le nombre de films réalisés pour chaque MES,
FONCTION STOCKÉE - EXEMPLE

Appel depuis SQL*PLUS :


SQL> SELECT prenom, nom, age(id)
FROM Artiste
WHERE id in (select MES from Film);
RESULTAT de la requêtes

Solution : Créer une procédure /fonction stockée


MANIPULATION DE PROGRAMME

• Création ou modification de sous-programme


CREATE [OR REPLACE] {PROCEDURE | FUNCTION} nom ...
• Recompilation automatique lors d’une modification
• Pour une compilation manuelle :
ALTER {PROCEDURE | FUNCTION} nom COMPILE
• Affichage des erreurs de compilation sous SQL*Plus :
SHOW ERRORS
• Suppression de sous-programme :
DROP {PROCEDURE | FUNCTION} nom
PROCÉDURE/FONCTION STOCKÉE - EXEMPLES
CREATE FUNCTION datePlus2 (n
VARCHAR2) RETURN NUMBER
CREATE OR REPLACE PROCEDURE coucou (n IS
number) an number;
IS BEGIN
Begin SELECT année into an from film
dbms_output.put_line (’bonjour ’ || WHERE titre = n;
to_char(n)); return an+2;
end ; END ;
/ /
-- exécution de la procédure -- exécution de la procédure

SQL> execute coucou(3); SQL> variable an number;


execute :an := datePlus2('titre1');
print an
PACKAGES

• Les packages
- Regrouper des types, variables, procédures, curseurs...
- Ensemble cohérent de services
• Encapsulation
- Accès extérieurs
- Accès privés (internes au paquetage)
PACKAGE – STRUCTURE

Deux sections:
• Section de spécification
Déclaration des variables et curseurs,
Déclaration sous-programmes accessibles depuis
l'extérieur
• Section d’implémentation
Sous-programmes accessibles en interne (privés)
CREATE PACKAGE gestionMES AS -- package spécification
FUNCTION nbFilms(idMES Film.MES%TYPE) RETURN INTEGER;
PROCEDURE filmParMES();
END gestionMES ;

CREATE PACKAGE BODY gestionMES AS -- package body


FUNCTION nbFilms(idMES Film.MES%TYPE) RETURN INTEGER IS nbFilm INTEGER;
BEGIN
SELECT COUNT(*) INTO nbFilm FROM Film WHERE MES = idMES; RETURN
nbFilm;
END nbFilms;

PROCEDURE filmParMES() IS
leMES Artiste%ROWTYPE;
BEGIN
FOR leMES IN lesMES() LOOP
DBMS_OUTPUT.PUT_LINE(leMES.prenom||’ ‘||leMES.nom);

END LOOP;
END filmParMES;
MANIPULATION D’UN PAQUETAGE
Référence : Uniquement sur les objets et programmes publics
nomPaquetage.nomObjet
nomPaquetage.nomSousProgramme(...)
Re-compilation d’un paquetage :
CREATE OR REPLACE PACKAGE
Erreurs de compilation avec SQL*Plus :
SHOW ERRORS
Suppression d’un paquetage :
DROP BODY nomPaquetage;
DROP nomPaquetage;
LES DECLENCHEURS
DÉCLENCHEUR (TRIGGERS)

Les déclencheurs :
• Permettent de gérer les contraintes d’intégrité personnalisées.
• Programme déclenché par un évènement:
AVANT ou APRES les événements suivants :
 Instruction LMD : INSERT, UPDATE, DELETE
 Instruction LDD : CREATE, ALTER, DROP
 Démarrage ou arrêt de la base
 Connexion ou déconnexion d’utilisateur
 Erreur d’exécution
• N’est pas appelé explicitement par une application
DÉCLENCHEUR - caractéristiques

Les Triggers ressemblent aux sous programmes stockés sur les points suivants :
• Sont des blocs PL/SQL nommés
• Objets stockés dans Oracle sous forme de code source et p-code (exécutable)
Mais ils en diffèrent sur les points suivants :
• Liés à un évènement : exécution implicite
• Ne sont pas paramétrables
• Peuvent être désactivés, etc....
DÉCLENCHEUR - utilisation

• Sécurité ou contrôle d’accès :


Ex: rendre les données disponibles uniquement dans les horaires de travail
• Audit ou logging :
Ex: Sauvegarder l’historique et avoir une traçabilité des opérations effectuées par les
utilisateurs
• Réplication des données
DÉCLENCHEUR – principe

Règle de production Déclencheur


Corps

(traitements)

Type ECA (Event- Condition- Action)


BEFORE Table AFTER

Evènement Evènement
SUR (avant /apres ) Evènement
INSERT INSERT
SI condition UPDATE UPDATE
DELETEt DELETEt
Alors Action
DÉCLENCHEUR - éléments

• Une instruction de déclenchement comporte les éléments suivants:


1. Moment du déclenchement : BEFORE (Avant) , AFTER ( Après)
2. Evènement déclencheur : INSERT, UPDATE ou DELETE
3. Nom de la table : ON table ou vue
4. Type de déclencheur : par table ou par ligne
• Par table : le corps du déclencheur s’exécute une seule fois une fois déclenché (par défaut )
• Par ligne : le corps du déclencheur s’exécute une fois pour chaque ligne concerné par
l’événement déclencheur
5. Clause WHEN : condition restrictive
6. Corps du déclencheur : bloc PL/SQL
DÉCLENCHEUR - séquence d’exécution

Instruction LMD :
INSERT INTO Film VALUES (132, 3, ‘titre2’, ‘2018’, 4739928, 5253637.766);

Action de déclenchement
Déclenchement sur table : BEFORE

Déclenchement sur ligne : BEFORE

Déclenchement sur ligne : AFTER


Déclenchement sur table : AFTER
DÉCLENCHEUR - syntaxe

CREATE [ OR REPLACE ] TRIGGER nom_Trigger


{ BEFORE | AFTER } évènement
ON nom_Table
DECLARE
-- déclarations variables, curseurs, records,...
BEGIN
-- traitement
EXCEPTION
-- Gestionnaires d’exceptions
END;
DÉCLENCHEUR – exemple

CREATE OR REPLACE TRIGGER secure_film


BEFORE INSERT OR UPDATE OR DELETE
ON FILM
BEGIN
IF (TO_CHAR(SYSDATE,’HH24:MI’)NOT BETWEEN ‘08:00’ AND ’18:00’
THEN
RAISE_application_error(-2322, ‘impossible de faire des
modifications hors horaire de travail’);
END IF;
END;
DÉCLENCHEUR – exemple2
CREATE OR REPLACE TRIGGER secure_film
BEFORE INSERT OR UPDATE OR DELETE
ON FILM
BEGIN
IF (TO_CHAR(SYSDATE,’HH24:MI’)NOT BETWEEN ‘08:00’ AND ’18:00’
THEN
IF INSERTING THEN
RAISE_application_error(-1001,‘Il est interdit d’insérer des données’);
ELSIF DELETING THEN
RAISE_application_error(-1002,‘Il est interdit de supprimer des données’);
ELSIF UPDATING (‘titre’) THEN
RAISE_application_error(-1003,‘Il est interdit de modifier le titre d’un film ’);
ELSE
DBMF_OUTPUT.PUT_LINE(‘La modification de la table film est possible seulement dans
les horaires de travail’);
END IF;
END;
DÉCLENCHEUR SUR LIGNE – syntaxe
CREATE [ OR REPLACE ] TRIGGER nom_Trigger
{BEFORE | AFTER} évènement1 [OR évènement2 OR évènement3]
ON nom_Table
[ REFERENCING OLD AS old | NEW AS new]
FOR EACH ROW
[ WHEN (condition) ]
DECLARE
-- déclarations variables, curseurs, records,...
BEGIN Corps du trigger
-- traitement
EXCEPTION
-- Gestionnaires d’exceptions
END;
DÉCLENCHEUR SUR LIGNE

REFERENCING : Changement des noms par défaut


• :OLD : désigne un enregistrement à effacer (déclencheur sur DELETE, UPDATE) :
REFERENCING OLD AS nomAncien
• :NEW : désigne un enregistrement à insérer (déclencheur sur INSERT, UPDATE) :
REFERENCING NEW AS nomNouveau
FOR EACH ROW
• Avec FOR EACH ROW : 1 exécution par ligne concernée par l’instruction LMD (row trigger)
• Sans FOR EACH ROW : 1 exécution par instruction LMD (statement trigger)
MANIPULATION D’UN DÉCLENCHEUR
• Tout déclencheur est actif dès sa compilation
• Recompilation d’un déclencheur après modification :
• ALTER TRIGGER nomDeclencheur COMPILE;
• Désactivation de déclencheurs :
• ALTER TRIGGER nomDeclencheur DISABLE;
• ALTER TABLE nomTable DISABLE ALL TRIGGERS;
• Réactivation de déclencheurs :
• ALTER TRIGGER nomDeclencheur ENABLE;
• ALTER TABLE nomTable ENABLE ALL TRIGGERS;
• Suppression d’un déclencheur :
• DROP TRIGGER nomDeclencheur;
DÉCLENCHEUR SUR LIGNE – exemple 1
CREATE OR REPLACE TRIGGER restrict_film
BEFORE UPDATE OF cout
ON Film
FOR EACH ROW
BEGIN
IF :NEW.cout > 3000000
THEN
RAISE_application_error(-2001,'impossible de modifier le cout de ce film');
END IF;
END;

SQL> UPDATE FILM SET cout= cout + 100000 where ID_MES=1;


DÉCLENCHEUR SUR LIGNE – exemple 2
CREATE OR REPLACE TRIGGER audit_film
AFTER DELETE OR INSERT OR UPDATE ON FILM
FOR EACH ROW
BEGIN
INSERT INTO audit_table_film ( user_name, times_user, old_id,
new_id, old_titre, new_titre, old_cout, new_cout, old_recette, new_recette)
VALUES ( USER,
SYSDATE, :OLD.idf, :NEW.idf, :OLD.titre, :NEW.titre,:OLD.cout, :NEW.cout,:OLD
.recette, :NEW.recette);
END;

SQL> UPDATE FILM SET cout= cout + 100000 WHERE ID_MES=1;


SQL> INSERT INTO film VALUES (555, 3, 'titre10', '2017', 8989585, 3454566);
SQL> DELETE FROM film WHERE id_mes=5;
DÉCLENCHEUR SUR LIGNE – exemple 3
CREATE OR REPLACE TRIGGER film_titre
BEFORE INSERT OR UPDATE OF cout ON FILM
FOR EACH ROW WHEN (NEW.id_MES=1)
BEGIN
IF UPDATING (‘cout’) THEN
IF :NEW.cout < :OLD.cout THEN
DBMS_OUTPUT.PUT_LINE(‘Attention !! ’);
RAISE_application_error(-3001,'interdit de modifier le cout des films ');
END IF;
ELSIF INSERTING THEN
IF :NEW.RECETTE - :NEW.COUT > 300000 THEN
DBMS_OUTPUT.PUT_LINE(‘le film a reussi ’);
END IF;
END IF;
END;

Vous aimerez peut-être aussi