Académique Documents
Professionnel Documents
Culture Documents
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 )
• 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.
• 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.
• 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 a:
• Une partie déclarations( optionnelle),
• Interactif :
• Exécution de code
• Stocké :
• Procédures, fonctions ou de triggers
• Appel interne :
• Programme :
• Appel depuis langages généralistes (JDBC)
STRUCTURE D’UN BLOC PL/SQL
Identifiants :
• 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
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;
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
• Concaténation: ||
• Affectation: :=
AFFICHAGE
• 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 := ¬e;
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 := ¬e;
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
• 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
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
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
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
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
• 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 ;
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
Evènement Evènement
SUR (avant /apres ) Evènement
INSERT INSERT
SI condition UPDATE UPDATE
DELETEt DELETEt
Alors Action
DÉCLENCHEUR - éléments
Instruction LMD :
INSERT INTO Film VALUES (132, 3, ‘titre2’, ‘2018’, 4739928, 5253637.766);
Action de déclenchement
Déclenchement sur table : BEFORE