Vous êtes sur la page 1sur 92

Département Technologies de l’Informatique

Atelier 1 
Implémentation de la base de
données et révision SQL
Objectifs
Comprendre l'origine des données et les liens entre elles (modèle relationnel).
Savoir créer des données avec le langage SQL (table).
Comprendre l'impact des types de données Savoir mettre à jour les données d'une base
Oracle (insert, update, delete) en SQL.
Savoir extraire les données d'une base ORACLE avec le SQL (select, where, like, ...).
Savoir écrire des requêtes SQL complexes (jointure, union, tri, ...).
Comprendre le principe de transaction (commit, rollback).

Pré-requis
Connaissance des concepts base de données, modèle relationnel et contraintes
d’intégrités.
Connaissance de Langage de définition et de manipulation de données en SQL.

SGBD Mohamed Fadhel SAAD-1


Département Technologies de l’Informatique

I. Base de données

Cette base de données décrit partiellement l’activité des employés rattachés à des
départements et travaillant dans des projets. Elle sert de support aux exemples du livre.

I Tables de la base de données


I.1 Table EMPLOYE
EMPLOYE (MATRICULE, ENOM, FONCTION, DATEREC, SALAIRE, COMMISSION,

NUMDEPT#)

Chaque employé est caractérisé par un matricule (identifiant), possède un nom, une
fonction (PRESIDENT, MANAGER, ANALYSTE, etc.), une date de recrutement, un
salaire, peut avoir une commission, et appartient à un département.

I.2 Table DEPARTEMENT


DEPARTEMENT (NUMDEPT, DNOM, LOCALITE)

Chaque département est caractérisé par un numéro (identifiant), et a un nom et une


localité.

I.3 Table PROJET


PROJET (NUMPROJ, PNOM, EMPLACEMENT)

Chaque projet est caractérisé par un numéro (identifiant), et a un nom et un


emplacement.

I.4 Table TRAVAILLER


TRAVAILLER (MATRICULE#, NUMPROJ#, NBRE_H)

Décrit le lien (plusieurs à plusieurs) entre les employés et les


projets. NBRE_H représente le nombre d’heures travaillées pour chaque employé
dans chaque projet.

II. Création de la base de données

CREATE TABLE (Attribut1 TYPE, Attribut2 TYPE, ...,


contrainte_integrité1,
contrainte_integrité2, ...);

Type des données :


• NUMBER(n) : Entier à n chiffres
• NUMBER(n, m) : Réel à n chiffres au total (virgule comprise), m après la virgule
• CHAR(n) : Chaîne de n caractères
• DATE : Date au format ‘JJ-MM-AAAA’

2-Mohamed Fadhel SAAD SGBD


Département Technologies de l’Informatique

Définitions des contraintes d’intégrité


• Clé primaire :
CONSTRAINT nom_contrainte PRIMARY KEY (attribut_clé [, attribut_clé2, …])
• Clé étrangère :
CONSTRAINT nom_contrainte FOREIGN KEY (attribut_clé_ét) REFERENCES table(attribut)
• Contrainte de domaine :
CONSTRAINT nom_contrainte CHECK (condition)

La création de la base de données se fait en plusieurs étapes :

1. Création des tables sans contraintes

/*---------------------------------------------------------- 
SUPPRESSION ET CREATION DES TABLES DE LA BASE : CREATEBD.sql 
------------------------------------------------------------*/ 
SET ECHO OFF 
PROMPT Suppression des tables  
DROP TABLE EMPLOYE      CASCADE CONSTRAINTS  

DROP TABLE DEPARTEMENT  CASCADE CONSTRAINTS  

DROP TABLE PROJET       CASCADE CONSTRAINTS  

DROP TABLE TRAVAILLER   CASCADE CONSTRAINTS  

 
PROMPT Création table EMPLOYE 
CREATE TABLE EMPLOYE 
(         MATRICULE NUMBER(4), 
         ENOM VARCHAR2(30), 
         FONCTION VARCHAR2(30), 
         DATEREC DATE, 
         SALAIRE NUMBER(8,3), 
         COMMISSION NUMBER(8,3), 
         NUMDEPT NUMBER(2) 


 
PROMPT Création table DEPARTEMENT 
CREATE TABLE DEPARTEMENT 

          NUMDEPT NUMBER(2), 
          DNOM VARCHAR2(40), 
          LOCALITE VARCHAR2(30) 


 
PROMPT Création table PROJET 
CREATE TABLE PROJET 

          NUMPROJ NUMBER(3), 
          PNOM VARCHAR2(40), 
          EMPLACEMENT VARCHAR2(30) 

SGBD Mohamed Fadhel SAAD-3


Département Technologies de l’Informatique


PROMPT Création table TRAVAILLER 
CREATE TABLE TRAVAILLER 

          MATRICULE NUMBER(4), 
          NUMPROJ NUMBER(3), 
          NBRE_H NUMBER(5) 


SET ECHO ON

2. Ajout des contraintes d’intégrité et des clés primaires et étrangères

/*---------------------------------------------------------- 
 CREATION DES CONTRAINTES : CONSTRAINTES_BD.sql 
------------------------------------------------------------*/ 
 
 
/*----------------------------------------------------------- 
 CONTRAINTES CLES PRIMAIRES 
--------------------------------------------------------------*/ 
ALTER TABLE EMPLOYE 
ADD CONSTRAINT PK_EMPLOYE  
PRIMARY KEY (MATRICULE) 

ALTER TABLE DEPARTEMENT         
ADD CONSTRAINT PK_DEPARTEMENT  
PRIMARY KEY (NUMDEPT) 

ALTER TABLE PROJET 
ADD CONSTRAINT PK_PROJET  
PRIMARY KEY (NUMPROJ) 

ALTER TABLE TRAVAILLER 
ADD CONSTRAINT PK_TRAVAILLER 
PRIMARY KEY (MATRICULE,NUMPROJ) 

/*----------------------------------------------------------- 
 CONTRAINTES CLES ETRANGERES 
--------------------------------------------------------------*/ 
 
ALTER TABLE EMPLOYE 
ADD CONSTRAINT   FK_EMPLOYE  
FOREIGN KEY (NUMDEPT) 
REFERENCES DEPARTEMENT(NUMDEPT) 

ALTER TABLE TRAVAILLER  
ADD CONSTRAINT   FK_TRAVAILLER_EMP 
FOREIGN KEY (MATRICULE)    
REFERENCES EMPLOYE (MATRICULE) 

 
ALTER TABLE TRAVAILLER  
ADD CONSTRAINT FK_TRAVAILLER_PROJ  
FOREIGN KEY (NUMPROJ) 

4-Mohamed Fadhel SAAD SGBD


Département Technologies de l’Informatique

REFERENCES PROJET (NUMPROJ) 


/

3. Chargement du contenu des tables

Ajout d’un tuple


INSERT INTO nom_table
VALUES (val_att1, val_att2, ...);

/*------------------------------------------------------------ 
CHARGEMENT DE LA BASE : INSERTION_BD.sql 
-------------------------------------------------------------*/ 
 
/*==============================*/ 
/* Chargement Table DEPARTEMENT */ 
/*==============================*/ 
SET ECHO OFF 
PROMPT   Chargement table DEPARTEMENT 
INSERT INTO DEPARTEMENT VALUES (10,’FINANCE’,’PARIS’) 

INSERT INTO DEPARTEMENT VALUES (20,’ADMINISTRATIF’,’BRUXELLES’) 

INSERT INTO DEPARTEMENT VALUES (30,’TECHNIQUE’,’LONDRES’) 

INSERT INTO DEPARTEMENT VALUES (40,’OPERATIONNEL’,’ATHENES’) 

 
/*=========================*/ 
/* Chargement Table PROJET */ 
/*=========================*/ 
 
PROMPT   Chargement table PROJET 
INSERT INTO PROJET  VALUES (10,’CONSTRUCTION D"UN CENTRE’,’PARIS’) 

INSERT INTO PROJET  VALUES (20,’PROGRAMME ROUTE DE L"EAU’,’BENIN’) 

INSERT INTO PROJET  VALUES (30,’ALIMENTATION EN EAU POTABLE’,’HAITI’) 

INSERT INTO PROJET  VALUES (40,’FORAGE PUITS’,’MADAGASCAR’) 

INSERT INTO PROJET  VALUES (50,’MAINTENANCE AERONAUTIQUE’,’LONDRES’) 

 
/*============================*/ 
/* Chargement Table EMPLOYE   */ 
/*============================*/ 
 
PROMPT   Chargement table EMPLOYE 
INSERT INTO EMPLOYE VALUES  
(7800, ’THOMAS’, ’PRESIDENT’, TO_DATE(’20-10-1980’,’dd-mm-yyyy’), 5000, null, 20) 

SGBD Mohamed Fadhel SAAD-5


Département Technologies de l’Informatique

INSERT INTO EMPLOYE VALUES  


(7600, ’BLAKE’, ’MANAGER’, TO_DATE(’10-6-1981’,’dd-mm-yyyy’), 2850, null, 30) 

INSERT INTO EMPLOYE VALUES  
(7780, ’CLARK’, ’MANAGER’, TO_DATE(’13-9-1985’,’dd-mm-yyyy’), 2450, null, 10 


INSERT INTO EMPLOYE VALUES  
(7566, ’JONES’, ’MANAGER’, TO_DATE(’12-4-1990’,’dd-mm-yyyy’), 2975, null, 10) 

INSERT INTO EMPLOYE VALUES  
(7788, ’SCOTT’, ’ANALYSTE’, TO_DATE(’13-07-1997’,’dd-mm-rr’), 3000, 200, 30) 

INSERT INTO EMPLOYE VALUES 
(7902, ’LOLA’, ’SECRÉTAIRE’, TO_DATE(’23-02-2005’,’dd-mm-yyyy’), 1750, null, 20) 

NSERT INTO EMPLOYE VALUES  
(7450, ’SMITH’, ’AGENT’,  TO_DATE(’7-2-2010’,’dd-mm-yyyy’), 800, null, 40) 

/*=============================*/ 
/* Chargement Table TRAVAILLER */ 
/*=============================*/ 
PROMPT   Chargement table TRAVAILLER 
INSERT INTO TRAVAILLER VALUES (7600, 30, 50) 

INSERT INTO TRAVAILLER VALUES (7450, 20,100) 

INSERT INTO TRAVAILLER VALUES (7600, 20,20) 

INSERT INTO TRAVAILLER VALUES (7780, 10,150) 

NSERT INTO TRAVAILLER VALUES (7902, 10,200) 

INSERT INTO TRAVAILLER VALUES (7600, 10,30) 

INSERT INTO TRAVAILLER VALUES (7566, 50,400) 

INSERT INTO TRAVAILLER VALUES (7800, 40,120) 

INSERT INTO TRAVAILLER VALUES (7902, 50,220) 

INSERT INTO TRAVAILLER VALUES (7600, 40,35) 

INSERT INTO TRAVAILLER VALUES (7566, 30,40) 

COMMIT 

SET ECHO ON

6-Mohamed Fadhel SAAD SGBD


Département Technologies de l’Informatique

Exercice 1
Mise à jour de la base de données

Mise à jour d’un attribut


UPDATE nom_table SET attribut=valeur
[WHERE condition];

Suppression de tuples
DELETE FROM nom_table [WHERE condition];

1. Augmenter le salaire de tous les employés de 10%.


2. Augmenter le salaire des employés de département finance de 15%.
3. Changer le département finance par le département comptabilité-finance.
4. Attribuer aux employés en poste avant le 01/0/195 (DATEREC) et ayant une commission
non spécifiée (NULL) une commission égale à la moyenne des commissions.
5. Supprimer l’employé ayant comme fonction PRESIDENT.
6. Annuler tous les changements de la base.

Exercice 2
Interrogation de la base de données

SELECT [ALL|DISTINCT] attribut(s) FROM table(s)


[WHERE condition]
[GROUP BY attribut(s) [HAVING condition]]
[ORDER BY attribut(s) [ASC|DESC]];

En utilisant SQL*Plus, exprimer les requêtes suivantes:


1. Nom, salaire, commission, salaire+commission de tous les managers.
2. Nom des managers par ordre décroissant de salaire.
3. Nom des managers dont la commission est inférieure à 25% de leur salaire.
4. Nombre d'employés du département n° 10.
5. Nombre d'employés ayant une commission.
6. Nombre de fonctions différentes.
7. Salaire moyen par fonction (sans tenir compte des commissions).
8. Total des salaires du département technique.
9. Nom des employés avec le nom de leur département.
10. Nom, fonction et salaire de l'employé ayant le salaire le plus élevé.
11. Nom des employés gagnant plus que ‘SCOTT’.
12. Nom, salaire des employés qui gagne plus que la moyenne des salaires des employés de
département commercial et moins que le minimum de département finance.
13. Nombre d’employés par département.
14. Total des salaires par département qui ont un nombre d’employés > 3.
15. Nom des employés occupant la même fonction que ‘SCOTT’.

SGBD Mohamed Fadhel SAAD-7


Département Technologies de l’Informatique

Atelier 2 
Développer un bloc simple
PL/SQL
Objectifs
Savoir écrire des blocs simples en respectant la syntaxe de base du langage PL/SQL.
Savoir déclarer et utiliser de variables simples.
Savoir déclarer et utiliser de variables composées.
Savoir utiliser des instructions SQL dans un bloc PL/SQL.

Pré-requis
Connaissance de Langage de définition et de manipulation de données en SQL.

8-Mohamed Fadhel SAAD SGBD


Département Technologies de l’Informatique
Généralités
PL/SQL : Langage procédural, Extension de SQL
- Déclaration de variables et de constantes
- Définition de sous-programmes
- Gestion des erreurs à l’exécution (exceptions)
- Manipulation de données avec SQL

Bloc PL/SQL
DECLARE
--Déclaration constantes/variables
BEGIN
--Commandes/instructions
EXCEPTION
--Traitement des erreurs à l’exé.
END;

SGBD Mohamed Fadhel SAAD-9


Département Technologies de l’Informatique

Déclarations
Partie déclarative d’un bloc PL/SQL ou d’un sous-programme
• Types usuels : INTEGER, REAL, STRING, DATE, BOOLEAN + types SQL

Exercice 1
Décrire les différents types de données en PL/SQL.

-----------------------------------------------------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------------------------------------------------
-----------------------------------------------------------------------------------------------------------------------------------
----------------------------------------------

1- Variables

identificateur nom_type [NOT NULL] [ { := DEFAULT} expression;  

Une seule déclaration par ligne est permise.

Déclaration simple d’une variable : exemple

-- declaration1.sql 
DECLARE  
  sexe CHAR(1);  
  /* déclaration d’une variable pour stocker le sexe d’une 
     personne (M ou F) */  
 
  i BINARY_INTEGER := 0; 
  /* déclaration d’un compteur initialisé à 0 */ 
 
  date_commande DATE := SYSDATE; 
  /* déclaration d’une variable pour stocker la date de création 
     d’une commande. La variable est initialisée à la date du 
     jour.*/ 
 
  message VARCHAR2(30) :=’Bonjour’; 
  /* déclaration d’une variable pour stocker un message, qui 
     est initialisée à ’Bonjour’ */ 
 
  note FLOAT := 10.5; 
  /* déclaration d’une variable pour stocker la note, qui est 
     initialisée à 10,5 */ 
 BEGIN 
 

10-Mohamed Fadhel SAAD SGBD


Département Technologies de l’Informatique

  NULL;  
 
END; 
/

2- Constantes

identificateur CONSTANT nom_type { := DEFAULT} expression;

Déclaration d’une constante : exemple

-- declaration2.sql 
DECLARE 
  pi NUMBER(8,5) :=3.14159; -- type de données SQL 
  min_salaire CONSTANT REAL := 1000.00; -- type de données SQL 
  trouve CONSTANT BOOLEAN := FALSE; -- type de données PL/SQL 
 
BEGIN 
  
  NULL; 
 
END; 
/

3- Déclaration par l’attribut %TYPE

identificateur1 nom_table.colonne%TYPE; 
identificateur2 nom_variable%TYPE;

Déclaration par référence variable : exemple

-- declaration3.sql 
DECLARE  
  nom EMPLOYE.ENOM%TYPE; 
  sal EMPLOYE.SALAIRE%TYPE; 
  /* déclaration de deux variables nom et sal ayant les mêmes 
    types de données que les champs ENOM et SALAIRE de la 
    table EMPLOYE */   
  
  min_salaire sal%type;  
  /* déclaration d’une variable min_salaire ayant le même  
    type de données que la variable sal */   
  
BEGIN 
 
  NULL;  
 
END; 
/

Paquetage DBMS_OUTPUT
Oracle possède un nombre de paquetages pour le développement des applications. Nous vous
présentons ici le paquetage DBMS_OUTPUT. Ce paquetage assure la gestion des entrées-sorties de
blocs PL/SQL.

SGBD Mohamed Fadhel SAAD-11


Département Technologies de l’Informatique

Les procédures du paquetage DBMS_OUTPUT les plus utiles pour la suite de ce cours sont :

- ENABLE : active les entrées-sorties.


- DISABLE : désactive les entrées-sorties.
- PUT (expression) : place l’expression à la fin du buffer de sortie, c’est-à-dire affiche l’expression à
l’écran.
- NEW_LINE : ajoute le caractère fin de ligne dans le buffer, c’est-à-dire qu’on fait un retour à la
ligne.
- PUT_LINE (expression) : appel de PUT suivi d’un appel de NEW_LINE.
- GET_LINE (out chaîne, out état) : lecture d’une ligne dans les paramètres chaîne, état prend la
valeur 0 si la valeur lue est valide.
- GET_LINES (out chaîne, in-out nbre_lignes) : permet la lecture de plusieurs lignes.

Avant d’utiliser ce paquetage, on doit l’activer au préalable avec la commande SET


SERVEROUTPUT ON. L’appel de toute procédure d’un paquetage se réalise avec l’instruction
nom_paquetage.nom_procédure (paramètres).

DBMS OUTPUT : exemple

Affichage des messages et des variables

-- affichage.sql 
-- activation du paquetage sous SQL*PLUS  
SET SERVEROUTPUT ON 
 
DECLARE 
  nom VARCHAR2(25) := ’THOMAS’; 
  fonct VARCHAR2(25) :=’PRESIDENT’; 
  sal NUMBER := 5000; 
 
BEGIN  
 
  DBMS_OUTPUT.ENABLE; -- Activation du paquetage sous PL/SQL 
  DBMS_OUTPUT.PUT_LINE(’Votre nom est        ’|| nom||’,’); 
  DBMS_OUTPUT.PUT_LINE(’votre fonction est   ’|| fonct||’,’); 
  DBMS_OUTPUT.PUT_LINE(’et votre salaire est ’|| sal||’.’); 
 
END; 
/

Résultat

Votre nom est        THOMAS, 


votre fonction est   PRESIDENT, 
et votre salaire est 5000.

12-Mohamed Fadhel SAAD SGBD


Département Technologies de l’Informatique

Affectation et expression
I.5 1. Affectation

nom_variable := expression;

Affectation classique : exemple n°1

Affectation et affichage de variables.

-- affectation1.sql 
SET SERVEROUTPUT ON 
 
DECLARE 
  a INTEGER; 
  b INTEGER; 
  c INTEGER; 
      
BEGIN 
 
-- affectation des variables 
  a := 1; 
  DBMS_OUTPUT.PUT_LINE(’A = ’|| a); 
  b := a+3; 
  DBMS_OUTPUT.PUT_LINE(’B = ’|| b); 
  a := 3; 
  DBMS_OUTPUT.PUT_LINE(’A = ’|| a); 
  b := 5; 
  DBMS_OUTPUT.PUT_LINE(’B = ’|| b); 
  c := a+b; 
  DBMS_OUTPUT.PUT_LINE(’C = ’|| c); 
  c := b-a; 
  DBMS_OUTPUT.PUT_LINE(’C = ’|| c); 
 
END; 
/

Résultat

A = 1 
B = 4 
A = 3 
B = 5 
C = 8 
C = 2

SGBD Mohamed Fadhel SAAD-13


Département Technologies de l’Informatique

Affectation_classique : exemple 2

Affectation et affichage de variables.

-- affectation2.sql 
SET SERVEROUTPUT ON 
DECLARE 
  /* on peut faire l’affectation dans la partie déclarative : 
     initialisation */ 
  salaire NUMBER; 
  heure_travail NUMBER := 40; 
  salaire_horaire NUMBER := 22.50; 
  bonus NUMBER := 100; 
  pays VARCHAR2(50); 
  nom VARCHAR2(50) := ’thomas’; 
  max_sal NUMBER := 700; 
  valide BOOLEAN 
 
BEGIN -- on peut faire l’affectation dans le corps du bloc 
  salaire := (salaire_horaire * heure_travail) + bonus; 
  nom := UPPER(nom); 
  pays := ’France’; 
  valide := (salaire > max_sal); 
  DBMS_OUTPUT.PUT_LINE(nom || ’ habite en ’|| pays); 
  DBMS_OUTPUT.PUT_LINE(’ Il gagne ’|| salaire); 
 
END; 
/

Résultat

THOMAS habite en France 


Il gagne 1000
 L’affectation avec l’instruction SELECT INTO. On place dans une variable le
résultat d’une requête.

SELECT INTO

SELECT champ_1,...,champ_n INTO v_1, ..., v_n 


FROM ...;

Cette instruction affecte aux variables v_1, ..., v_n les valeurs retournées par la
requête.

SELECT INTO : exemple

Écrire un bloc PL/SQL qui permet d’afficher le matricule de l’employé THOMAS. 

-- affectation3.sql 
SET SERVEROUTPUT ON  
 
DECLARE 

14-Mohamed Fadhel SAAD SGBD


Département Technologies de l’Informatique

  num NUMBER; 
  nom_emp VARCHAR2(30) := ’THOMAS’; 
 
BEGIN 
 
-- affectation des variables par l’instruction SELECT ... INTO 
  SELECT MATRICULE INTO num 
  FROM EMPLOYE 
  WHERE ENOM= nom_emp; 
  DBMS_OUTPUT.PUT_LINE 
  (’L’’employé ’||nom_emp||’ a pour matricule ’ ||num); 
 
END; 
/

Résultat

L’employé THOMAS a pour matricule 7800


 Remarque
Il faut faire attention, la requête doit retourner un et un seul résultat, sinon, une
erreur se produit lors de l’exécution.

I.6 2. Expression
I.6.1 a. Opérateur de concaténation
L’opérateur || permet de concaténer plusieurs chaînes non nécessairement de même taille, en une
seule.

Opérateur de concaténation : exemple

Concaténation de deux chaînes de caractères.

-- concatenation.sql 
SET SERVEROUTPUT ON 
 
DECLARE 
  chaîne1 VARCHAR2(5) := ’infor’; 
  chaîne2 VARCHAR2(7) := ’matique’; 
  chaîne3 VARCHAR2(12); 
 
BEGIN 
 
-- concaténation 
  chaîne3 := chaîne1 || chaîne2;  
  DBMS_OUTPUT.PUT_LINE (chaîne3); 
 
END; 
/

Résultat

informatique

Priorité des opérateurs : exemple

SGBD Mohamed Fadhel SAAD-15


Département Technologies de l’Informatique

Évaluer les expressions suivantes :

-- priorite.sql 
SET SERVEROUTPUT ON  
 
DECLARE 
  a INTEGER := 1+3**3; 
  b INTEGER := (1+3)**3; 
  c INTEGER := ((1+3)*(4+5))/6; 
  d INTEGER := 2**2*3**2; 
  e INTEGER := (2**2)*(3**2); 
 
BEGIN 
 
  DBMS_OUTPUT.PUT_LINE(’a = ’ || a); 
  DBMS_OUTPUT.PUT_LINE(’b = ’ || b); 
  DBMS_OUTPUT.PUT_LINE(’c = ’ || c); 
  DBMS_OUTPUT.PUT_LINE(’d = ’ || d); 
  DBMS_OUTPUT.PUT_LINE(’e = ’ || e); 
 
END; 
/

Résultat

a = 28 
b = 64 
c = 6 
d = 36 
e = 36

16-Mohamed Fadhel SAAD SGBD


Département Technologies de l’Informatique

Outils de mise au point


1. Variables de substitution
SQL*Plus permet à un bloc PL/SQL de recevoir des informations d’entrée à l’aide de variables
nommées variables de substitution. Elles ne peuvent pas être utilisées comme variables de sortie, car
aucune mémoire n’est allouée pour elles.

Variable de substitution : exemple

À partir d’un matricule d’un employé (variable de substitution), sélectionner le nom,


la fonction et le salaire, puis afficher à l’écran le résultat en utilisant la procédure
standard regroupée dans le package DBMS_OUTPUT  fourni avec le noyau d’Oracle.

-- substitution.sql 
SET SERVEROUTPUT ON 
 
DECLARE 
  mat NUMBER := &s_mat; -- variable de substitution  
  -- On suppose que le matricule saisi est correct  
  nom EMPLOYE.ENOM%TYPE; 
  fonct EMPLOYE.FONCTION%TYPE; 
  sal EMPLOYE.SALAIRE%TYPE; 
 
BEGIN 
 
  SELECT ENOM, FONCTION, SALAIRE 
  INTO nom, fonct, sal 
  FROM EMPLOYE 
  WHERE MATRICULE = mat; 
  DBMS_OUTPUT.PUT_LINE (’L’’employé de nom ’||nom); 
  DBMS_OUTPUT.PUT_LINE (’Sa fonction est  ’|| fonct); 
  DBMS_OUTPUT.PUT_LINE (’Son salaire est  ’|| sal); 
 
END; 
/

Résultat

Entrez une valeur pour s_mat : 7800 


ancien   2 :    mat NUMBER := &s_mat; 
nouveau   2 :    mat NUMBER := 7800; 
L’employé de nom THOMAS  
Sa fonction est  PRESIDENT  
Son salaire est  5000  

Avec la variable de substitution, on peut utiliser la directive  ACCEPT (lecture de la variable au


clavier).

Variable substitution ACCEPT : exemple

SGBD Mohamed Fadhel SAAD-17


Département Technologies de l’Informatique

Le même exemple précédent, mais en utilisant la directive ACCEPT  .

-- sub_accept.sql 
ACCEPT s_mat PROMPT ’Entrer Matricule Employé : ’ 
SET SERVEROUTPUT ON  
DECLARE 
  nom EMPLOYE.ENOM%TYPE; 
  fonct EMPLOYE.FONCTION%TYPE; 
  sal EMPLOYE.SALAIRE%TYPE; 
 
BEGIN 
 
  SELECT ENOM, FONCTION, SALAIRE 
  INTO nom, fonct, sal 
  FROM EMPLOYE 
  WHERE MATRICULE = &s_mat; 
  DBMS_OUTPUT.PUT_LINE (’L’’employé de nom ’||nom); 
  DBMS_OUTPUT.PUT_LINE (’Sa fonction est  ’|| fonct); 
  DBMS_OUTPUT.PUT_LINE (’Son salaire est  ’|| sal); 
 
END; 
/
 Remarque
Il faut exécuter le bloc à l’aide de la commande START  et non pas par copier-coller
d’un éditeur de texte vers la fenêtre SQL*Plus (à cause des instructions
d’entrée ACCEPT).

I.7 2. Variables de session


Les variables de session sont des variables globales, nommées aussi variables hôte. Elles sont définies
dans l’environnement hôte du programme PL/SQL (SQL*Plus, Forms Developer...) et elles sont
appelées dans le bloc PL/SQL.
Sous SQL*Plus, la déclaration d’une telle variable hôte est faite avant le bloc PL/SQL et en utilisant la
directive VARIABLE.
Dans le code, il faut préfixer le nom de la variable de session du symbole ":". L’affichage de la
variable sous SQL*Plus est réalisé par la directive  PRINT. L’exemple suivant illustre l’utilisation
d’une variable de session.

Variable de session : exemple

Soit deux variables de session, écrire un bloc PL/SQL qui permet d’initialiser les deux
variables puis de les permuter et enfin d’afficher les contenus des variables.  

-- variable_ses.sql 
VARIABLE g_x NUMBER; 
VARIABLE g_y NUMBER; 
 
DECLARE 
  z NUMBER; 
 
BEGIN 
:g_x := 10; 
:g_y := 15; 
z    := :g_x; 
:g_x := :g_y; 

18-Mohamed Fadhel SAAD SGBD


Département Technologies de l’Informatique

:g_y := z; 
 
END; 

PRINT g_x; 
PRINT g_y;

Résultat

       G_X  
----------  
       15  
      G_Y  
----------  

       10

SGBD Mohamed Fadhel SAAD-19


Département Technologies de l’Informatique

Série d’exercices

Exercice 1
Exécuter les scripts suivants, détecter les erreurs s’ils existent et les corrigent.

Exemple 2.1

DECLARE
acct_id INTEGER(4)NOT NULL := 9999;
a NATURALN := 9999;
b POSITIVEN := 9999;
c SIMPLE_INTEGER := 9999;
chaine_vide VARCHAR2(80) := TO_CHAR('');
addresse VARCHAR2(80);
code_postal VARCHAR2(80) := SUBSTR(address, 25, 0);
nom VARCHAR2(80);
valide BOOLEAN := (name != '');

BEGIN
NULL;
END;

Exemple 2.2

DECLARE
nom_emp1 employe.enom%TYPE;
nom_emp2 VARCHAR(25) NOT NULL := 'Mohamed';
nom_emp3 employe.enom%TYPE := 'Amir';

BEGIN
DBMS_OUTPUT.PUT_LINE('nom employe 1=' || nom_emp1);
DBMS_OUTPUT.PUT_LINE('nom employe 2=' || nom_emp2);
DBMS_OUTPUT.PUT_LINE('nom employe 3=' || nom_emp3);
END;

Exemple 2.3

DECLARE
dept_rec departement%ROWTYPE;
BEGIN
-- Affectez des valeurs à des champs :
dept_rec.numdept := 50;
dept_rec.dnom := 'Administration';
dept_rec.localite := 'Tunis';
-- Affichage:
DBMS_OUTPUT.PUT_LINE('dept_num: ' || dept_rec.numdept);
DBMS_OUTPUT.PUT_LINE('dept_nom: ' || dept_rec.dnom);
DBMS_OUTPUT.PUT_LINE(' dept_localite: ' || dept_rec.localite);
-- Insertion dans la table departement:

INSERT INTO departement VALUES dept_rec;


COMMIT;
END;

20-Mohamed Fadhel SAAD SGBD


Département Technologies de l’Informatique

Exercice 2
1. Ecrire un bloc PL/SQL affectant les valeurs 1 et 2 à deux variables a et b, puis permutant les
valeurs de ces deux variables.
2. Écrire un programme PL/SQL, qui à partir de deux entiers donnés affiche le total et la
moyenne.

Exercice 3
1. Ecrire un bloc PL/SQL permettant de permuter le salaire des employés numéro 2000 et
2300.
2. Ecrire un bloc PL/SQL qui permet d’afficher le message suivant pour l’empoyé de numéro
1000:
Monsieur <Mohamed Tlili> est recrute comme <Ouvrier> avec un salaire de <350> ‘.

Exercice 4
1. Créer un bloc PL/SQL pour insérer un nouveau département dans la table
DEPARTEMENT. Créer un paramètre pour le numéro du département (saisir 60). Laisser le
nom et la localité à NULL.
2. Afficher le nouveau département.
3. Ecrire un PL/SQL permettant d’affecter la valeur ‘Personnel’ pour le nom du département et
la valeur ‘Paris’ pour la localité du département.
4. Créer un bloc PL/SQL pour supprimer le département créé précédemment.

SGBD Mohamed Fadhel SAAD-21


Département Technologies de l’Informatique

Atelier 3 
Traitements conditionnels et
traitements répétitifs
Objectifs
Ecrire des blocs PL/SQL en utilisant les instructions de contrôle.

Pré-requis
Connaissance de Langage de définition et de manipulation de données en SQL.
Création des blocs simples PL/SQL.
Déclaration et manipulation des identificateurs de PL/SQL.

22-Mohamed Fadhel SAAD SGBD


Département Technologies de l’Informatique
Généralités
Parmi les instructions de contrôle, on distingue :
Les structures conditionnelles :
- L’instruction IF.
- L’instruction CASE.
Les structures itératives :
- La boucle de base LOOP permet de répéter une série d’instructions sans condition globale.
- La boucle FOR permet de contrôler le nombre d’itérations grâce à un indice.
- La boucle WHILE permet de contrôler les itérations selon la vérification d’un prédicat.
Conditions logiques
Les opérateurs de comparaison en PL/SQL sont :
- Les opérateurs relationnels habituels : >, <, <=, >=, Différent (<>, !=, ~=, ˆ=)

- L’opérateur IS NULL. Il retourne la valeur booléenne TRUE, si l’opérande est NULL, et retourne


FALSE s’il n’est pas NULL. L’opérateur IS NOT NULL retourne le résultat contraire.

- L’opérateur LIKE. Il permet d’effectuer une comparaison partielle d’un caractère, une chaîne ou
une valeur CLOB à un modèle et retourne TRUE si la valeur correspond au modèle et FALSE si elle
ne lui correspond pas.
Le modèle est une expression qui peut contenir des lettres, des chiffres et en plus les deux caractères
spéciaux suivants :
’%’ représente n’importe quelle séquence de 0 ou plusieurs caractères.
’_’ représente un seul caractère quelconque.

- L’opérateur BETWEEN. Il permet de déterminer si la valeur d’une expression donnée appartient à


un intervalle bien défini. L’intervalle est généralement un intervalle numérique ou un intervalle du
type Date.

- L’opérateur IN. Il permet de déterminer si la valeur d’un champ donné appartient à une liste de
valeurs prédéfinies. Les valeurs dans la liste sont généralement des valeurs numériques, des valeurs du
type chaîne ou des valeurs du type Date.

- Les opérateurs logiques AND (Et logique), OR (Ou logique) et NOT (Négation logique). Ils sont


utilisés pour construire une expression booléenne complexe en combinant des conditions simples.
Lorsque l’on combine plusieurs expressions booléennes par des opérateurs logiques, le résultat final de
la condition complexe dépend de l’ordre d’exécution des différentes conditions. Cet ordre est
déterminé par la priorité des opérateurs logiques.

 Voici l’ordre prédéfini :


1-Le résultat logique (TRUE, FALSE) des comparaisons (=, <, >, etc.).
2-Les négations (NOT).
3-Les AND.
4-Les OR.

 Pour modifier cet ordre d’exécution, nous pouvons utiliser des parenthèses afin de grouper les
différentes conditions logiques.

SGBD Mohamed Fadhel SAAD-23


Département Technologies de l’Informatique

Traitements conditionnels
1. La commande IF simple

IF condition THEN 
  instructions; 
END IF;

IF-THEN : exemple

Utilisation des instructions conditionnelles simples.

-- si_simple.sql 
SET SERVEROUTPUT ON  
 
DECLARE 
-- déclaration des variables 
  message VARCHAR2(30) :=’bonjour les amis’; 
  note FLOAT := 10.5; 
 
BEGIN 
 
-- instructions conditionnelles simples 
  IF message IS NOT NULL   THEN 
     DBMS_OUTPUT.PUT_LINE(’message non nul’ ); 
  END IF; 
 
  IF LENGTH(message) > 0   THEN 
     DBMS_OUTPUT.PUT_LINE(’message non vide ’); 
  END IF; 
 
  IF message LIKE ’%ami%’ AND LENGTH(message) > 0   THEN 
     DBMS_OUTPUT.PUT_LINE 
     (’message non vide, contenant le mot ami’); 
  END IF;  
  IF note between 10 AND 12   THEN 
     DBMS_OUTPUT.PUT_LINE(’note entre 10 et 12’ ); 
  END IF; 
 
END; 
/

Résultat

message non nul 

message non vide 

message non vide, contenant le mot ami 

note entre 10 et 12

24-Mohamed Fadhel SAAD SGBD


Département Technologies de l’Informatique

2. La commande IF-THEN-ELSE

IF condition THEN 
  instructions_1; 
ELSE 
  instructions_2; 
END IF;

IF-THEN-ELSE : exemple

Écrire un bloc PL/SQL qui permet d’augmenter le salaire d’un employé, selon le
nombre d’heures de travail dans des projets. Quand ce nombre dépasse 200, une
allocation de 1 000 euros est accordée, sinon l’allocation est de 500 euros.

-- si_sinon.sql 
SET SERVEROUTPUT ON 
 
DECLARE 
-- déclaration des variables 
  quota TRAVAILLER.NBRE_H%TYPE;  
  bonus EMPLOYE.SALAIRE%TYPE;  
  sal EMPLOYE.SALAIRE%TYPE;  
  emp_id EMPLOYE.MATRICULE%TYPE :=7566;  
 
BEGIN  
 
-- sélection du nombre des heures de travail   
  SELECT SUM(NBRE_H)  
  INTO quota 
  FROM TRAVAILLER 
  WHERE MATRICULE = emp_id; 
 
-- sélection du salaire 
  SELECT SALAIRE  
  INTO sal 
  FROM EMPLOYE 
  WHERE MATRICULE = emp_id; 
 
-- détermination du bonus 
  IF quota > 200 THEN  
     bonus := 1000;  
   ELSE 
     bonus := 500;  
  END IF; 
  DBMS_OUTPUT.PUT_LINE(’Employé de Matricule’ || emp_id ||’ a le 
salaire ’ || sal  || ’ et travaille ’ || quota || ’ heures dans des projets’) 
 
-- modification du salaire 
  UPDATE employe  
  SET salaire = salaire + bonus  
  WHERE MATRICULE = emp_id; 
 
-- sélection du salaire après modification 

SGBD Mohamed Fadhel SAAD-25


Département Technologies de l’Informatique

  SELECT SALAIRE  
  INTO sal 
  FROM EMPLOYE 
  WHERE MATRICULE = emp_id; 
 
  DBMS_OUTPUT.PUT_LINE(’Employé de Matricule ’ || emp_id || ’, 
son nouveau salaire est ’ || sal); 
ROLLBACK; 
END; 
/

Résultat

Employé de Matricule 7566 a le salaire 2975 et travaille 440 heures


dans des projets  

Employé de Matricule 7566, son nouveau salaire est 3975  

3. La commande IF imbriquée

IF condition THEN 
  [IF condition_1 THEN 
     ...; 
  ] 
[ELSE 
   IF condition_2 THEN 
     ...; 

END IF;

 Remarque
Le niveau d’imbrication n’a pas de limite.

IF_imbriquée : exemple 1

Écrire un bloc PL/SQL qui permet d’augmenter le salaire d’un employé particulier,
selon le nombre des heures de travail (quota) dans des projets :

 salaire = salaire + 0.1 * quota, si quota <= 100,

 salaire = salaire + 0.2 * quota, si 100 < quota <= 200,

 salaire = salaire + 0.3 * quota, si 200 < quota <= 300,

 salaire = salaire + 0.4 * quota, si quota >300.

-- si_imbrique1.sql 
SET SERVEROUTPUT ON 
 
DECLARE  
-- déclaration des variables  
  quota TRAVAILLER.NBRE_H%TYPE;  
  bonus EMPLOYE.SALAIRE%TYPE;  

26-Mohamed Fadhel SAAD SGBD


Département Technologies de l’Informatique

  sal EMPLOYE.SALAIRE%TYPE;  
  emp_id EMPLOYE.MATRICULE%TYPE :=7566;  
 
BEGIN  
-- sélection du nombre des heures de travail 
  SELECT SUM(NBRE_H)  
  INTO quota 
  FROM TRAVAILLER 
  WHERE MATRICULE = emp_id; 
 
-- sélection du salaire 
  SELECT SALAIRE  
  INTO sal 
  FROM EMPLOYE 
  WHERE MATRICULE = emp_id; 
 
-- détermination du bonus 
  IF quota <= 100 THEN  
     bonus := 0.1*quota;  
  ELSE 
     IF quota <= 200 THEN  
        bonus := 0.2*quota; 
     ELSE  
        IF quota <= 300 THEN  
           bonus := 0.3*quota; 
        ELSE 
           bonus := 0.4*quota; 
        END IF; 
     END IF; 
  END IF; 
 
  DBMS_OUTPUT.PUT_LINE(’Employé de Matricule’ || emp_id ||’ a le 
salaire ’ || sal  || ’ et travaille ’ || quota || ’ heures dans des 
projets’); 
 
-- modification du salaire 
   UPDATE employe  
   SET salaire = salaire + bonus  
   WHERE MATRICULE = emp_id;  
 
-- sélection du salaire après modification 
   SELECT SALAIRE  
   INTO sal 
   FROM EMPLOYE    WHERE MATRICULE = emp_id; 
 
   DBMS_OUTPUT.PUT_LINE(’Employé de Matricule ’ || emp_id || ’, 
son nouveau salaire est ’ || sal); 
ROLLBACK; 
 
END; 
/

Résultat

Employé de Matricule 7566 a le salaire 2975 et travaille 440


heures dans des projets  

SGBD Mohamed Fadhel SAAD-27


Département Technologies de l’Informatique

Employé de Matricule 7566, son nouveau salaire est 3151

4. La commande IF-THEN-ELSIF

On peut remplacer la commande IF imbriquée par la commande IF-THEN-ELSIF et cela, pour des


raisons de lisibilité. Si l’instruction dans la clause  ELSE consiste en un autre IF, il est préférable
d’utiliser la clause ELSIF.
Il est recommandé d’indenter les conditions.

IF condition_1 THEN 
  instructions_1; 
[ELSIF condition_2 THEN 
  instructions_2;] 
[ELSIF condition_3 THEN 
  instructions_3;] 
   ... 
 
[ELSE 
  instructions_else;]  
END IF;

 Remarque
Il n’y a pas de limites au nombre de ELSIF.

IF THEN-ELSIF : exemple 1

Réécrire le bloc PL/SQL de l’exemple n°1 de la commande IF  imbriquée, en utilisant


la commande  IF-THEN-ELSE.

-- si_sinonsi1.sql 
SET SERVEROUTPUT ON 
 
DECLARE  
-- déclaration des variables 
  quota TRAVAILLER.NBRE_H%TYPE;  
  bonus EMPLOYE.SALAIRE%TYPE;  
  sal EMPLOYE.SALAIRE%TYPE;  
  emp_id EMPLOYE.MATRICULE%TYPE :=7566;  
 
BEGIN  
 
-- sélection du nombre des heures de travail 
  SELECT SUM(NBRE_H)  
  INTO quota 
  FROM TRAVAILLER 
  WHERE MATRICULE = emp_id; 
 
-- sélection du salaire 
  SELECT SALAIRE  
  INTO sal 
  FROM EMPLOYE 

28-Mohamed Fadhel SAAD SGBD


Département Technologies de l’Informatique

  WHERE MATRICULE = emp_id; 


 
-- détermination du bonus 
  IF quota <= 100 THEN  
     bonus := 0.1*quota;  
  ELSIF quota <= 200 THEN  
     bonus := 0.2*quota; 
  ELSIF quota <= 300 THEN  
     bonus := 0.3*quota; 
  ELSE 
     bonus := 0.4*quota; 
  END IF;      
 
  DBMS_OUTPUT.PUT_LINE(’Employé de Matricule’ || emp_id ||’ a le 
salaire ’ || sal  || ’ et travaille ’ || quota || ’ heures dans des 
projets’); 
-- modification du salaire 
  UPDATE EMPLOYE  
  SET SALAIRE = SALAIRE + bonus  
  WHERE MATRICULE = emp_id;  
 
-- sélection du salaire après modification 
  SELECT SALAIRE  
  INTO sal 
  FROM EMPLOYE 
  WHERE MATRICULE = emp_id; 
 
  DBMS_OUTPUT.PUT_LINE(’Employé de Matricule ’ || emp_id || ’, 
son nouveau salaire est ’ || sal); 
  ROLLBACK; 
END; 
/
5. La commande CASE

a. La commande CASE simple

CASE selecteur 
  WHEN expression_1 THEN instructions_1; 
  WHEN expression_2 THEN instructions_2; 
  ... 
  WHEN expression_n THEN instructions_n; 
[ELSE  
  instructions_else;] 
END CASE;

CASE simple : exemple

Écrire un bloc PL/SQL qui, à partir d’une appréciation donnée, affiche la mention
associée.

-- cas_simple.sql 
SET SERVEROUTPUT ON 
 
DECLARE 

SGBD Mohamed Fadhel SAAD-29


Département Technologies de l’Informatique

  app CHAR(1); 
BEGIN 
 
  app := ’B’; 
-- affichage de la mention 
  CASE app 
      WHEN ’A’ THEN DBMS_OUTPUT.PUT_LINE(’Excellent’); 
      WHEN ’B’ THEN DBMS_OUTPUT.PUT_LINE(’Très bien’); 
      WHEN ’C’ THEN DBMS_OUTPUT.PUT_LINE(’Bien’); 
      WHEN ’D’ THEN DBMS_OUTPUT.PUT_LINE(’Passable’); 
      WHEN ’F’ THEN DBMS_OUTPUT.PUT_LINE(’Faible’); 
  ELSE  
      DBMS_OUTPUT.PUT_LINE(’ appréciation inconnue !!!’); 
  END CASE; 
 
END; 
/

Résultat

Très Bien

b. La commande CASE de recherche


CASE  
  WHEN condition_1 THEN instructions_1; 
  WHEN condition_2 THEN instructions_2; 
  ... 
  WHEN condition_n THEN instructions_n; 
[ELSE  
  instructions_else;] 
END CASE;

La commande CASE de recherche exécute les premières instructions ( instructions_1), si la première


condition est vérifiée, sinon elle passe à la condition suivante...
Si aucune condition n’est vraie et que l’instruction  ELSE n’existe pas dans la commande, alors
l’exception prédéfinie CASE_NOT_FOUND est soulevée.

CASE recherche : exemple

Écrire un bloc PL/SQL qui, à partir d’une moyenne donnée, affiche la mention
associée.

-- cas_recherche.sql 
SET SERVEROUTPUT ON 
 
DECLARE 
  moyenne NUMBER(4,2) :=13.50; 
 
BEGIN 
 
 CASE  
 WHEN moyenne between 18 and 20  THEN 

30-Mohamed Fadhel SAAD SGBD


Département Technologies de l’Informatique

     DBMS_OUTPUT.PUT_LINE(’Excellent’); 
 WHEN moyenne between 16 and 17.99 THEN 
     DBMS_OUTPUT.PUT_LINE(’Très Bien’); 
  WHEN moyenne between 14 and 15.99 THEN 
      DBMS_OUTPUT.PUT_LINE(’Bien’); 
  WHEN moyenne between 12 and 13.99 THEN 
      DBMS_OUTPUT.PUT_LINE(’Assez bien’); 
  WHEN moyenne between 10 and 11.99 THEN  
      DBMS_OUTPUT.PUT_LINE(’Passable’); 
  WHEN moyenne between 0 and 9.99 THEN  
      DBMS_OUTPUT.PUT_LINE(’Redouble’); 
  ELSE  
     DBMS_OUTPUT.PUT_LINE(’Moyenne inconnue !!!’); 
  END CASE; 
 
END; 
/

Résultat

Assez bien

SGBD Mohamed Fadhel SAAD-31


Département Technologies de l’Informatique

Traitements répétitifs
1. La boucle de base LOOP

PL/SQL offre plusieurs structures pour répéter un ensemble d’actions. La plus simple est appelée
boucle de base sans contrôle. Chaque fois que le flux d’exécution atteint le  END LOOP, le contrôle est
renvoyé à la partie supérieure de la boucle, qui est l’instruction  LOOP. Pour éviter une boucle infinie,
on ajoute la commande EXIT.
Pour quitter l’itération en cours et céder le contrôle à la prochaine itération, on utilise l’instruction
CONTINUE.

LOOP 
  instructions; 
  ... 
  [EXIT [WHEN condition_1;]] 
  ... 
  [CONTINUE [WHEN condition_2;]] 
  ... 
END LOOP; 

EXIT, sans la partie optionnelle (WHEN condition_1), permet de quitter une boucle
d’une manière inconditionnelle. La clause WHEN contrôle la sortie de la boucle lorsque
la condition (condition_1) est vraie.

CONTINUE, sans la partie optionnelle (WHEN condition_2), permet de passer à


l’itération suivante d’une manière inconditionnelle. La clause WHEN contrôle le
passage à l’itération suivante lorsque la condition (condition_2) est vraie.

 Remarque
Une boucle sans  EXIT est une boucle infinie.

LOOP_base : exemple

Écrire un bloc PL/SQL qui permet d’afficher la table de multiplication.

-- boucle_base.sql 
SET SERVEROUTPUT ON 
 
DECLARE 
  i PLS_INTEGER := -1; 
  j PLS_INTEGER; 
  m PLS_INTEGER; 
 
BEGIN 
 
  DBMS_OUTPUT.PUT_LINE(’Table de Multiplication’); 
  DBMS_OUTPUT.PUT_LINE(’=======================’); 
 
  LOOP 
     i := i + 1; 
     DBMS_OUTPUT.PUT_LINE(’Multiples de ’ || i); 

32-Mohamed Fadhel SAAD SGBD


Département Technologies de l’Informatique

     j := -1; 
     LOOP 
        j := j + 1; 
        m := i * j; 
        DBMS_OUTPUT.PUT_LINE(i || ’ * ’ || j || ’ = ’ || m); 
     EXIT WHEN (j = 9); 
     END LOOP; 
  EXIT WHEN (i = 9); 
  END LOOP;  
 
END; 
/

LOOP base-CONTINUE  : exemple

Écrire un bloc PL/SQL qui permet d’afficher la table de multiplication des nombres
impairs.

-- boucle_base_continue.sql 
SET SERVEROUTPUT ON 
 
DECLARE 
  i PLS_INTEGER := -1; 
  j PLS_INTEGER; 
  m PLS_INTEGER; 
 
BEGIN 
   DBMS_OUTPUT.PUT_LINE 
  (’Table de Multiplication des nombres pairs’); 
   DBMS_OUTPUT.PUT_LINE  
  (’=========================================’); 
  LOOP 
     i := i + 1; 
  CONTINUE WHEN MOD(i,2)=0; 
     DBMS_OUTPUT.PUT_LINE(’Multiple de ’ || i); 
     j := -1; 
     LOOP 
        j := j + 1; 
        m := i * j; 
        DBMS_OUTPUT.PUT_LINE(i || ’ * ’ || j || ’ = ’ || m); 
     EXIT WHEN (j = 9); 
     END LOOP; 
  EXIT WHEN (i = 9); 
  END LOOP; 
 
END; 
/

2. La boucle WHILE
WHILE condition LOOP 
  instructions; 
  ... 
END LOOP;

SGBD Mohamed Fadhel SAAD-33


Département Technologies de l’Informatique

 Remarque
Les variables impliquées dans la condition de répétition doivent être mises à jour à
l’intérieur de la boucle. Si les variables ne sont pas modifiées, alors la condition
reste TRUE  et la boucle est sans arrêt.

WHILE : exemple

Écrire un bloc PL/SQL qui permet de calculer la somme des 100 premiers entiers, en
utilisant la boucle WHILE.

-- tant_que.sql 
SET SERVEROUTPUT ON 
 
DECLARE 
  somme NUMBER(4) := 0; 
  i NUMBER(3) := 1; 
 
BEGIN    
 
  WHILE (i <= 100) LOOP 
     somme := somme+ i;  
     i := i + 1;  
  END LOOP; 
 
  DBMS_OUTPUT.PUT_LINE(’La Somme est ’ || somme); 
 
END; 
/

Résultat

La Somme est : 5050

3. La boucle FOR

FOR compteur IN [REVERSE] valeur_inf..valeur_sup LOOP 


  instructions; 
  ... 
END LOOP;

 Remarque
Le compteur est déclaré implicitement comme un entier. Il n’est pas nécessaire de
le déclarer.

FOR : exemple

Écrire un bloc PL/SQL qui permet de calculer la somme des 100 premiers entiers, en
utilisant la boucle FOR.

-- pour.sql 
SET SERVEROUTPUT ON 
 

34-Mohamed Fadhel SAAD SGBD


Département Technologies de l’Informatique

DECLARE 
  somme NUMBER(4) := 0; 
 
BEGIN    
 
  FOR i IN 1..100 LOOP 
     somme := somme+ i; 
  END LOOP; 
 
  DBMS_OUTPUT.PUT_LINE(’La Somme est ’ || somme); 
 
END; 
/

Résultat

La Somme est : 5050

SGBD Mohamed Fadhel SAAD-35


Département Technologies de l’Informatique

Série d’exercices

Exercice 1
Exécuter les scripts suivants, détecter les erreurs s’ils existent et les corrigent.

Exemple 3.1

DECLARE
v_telephone CHAR(14) NOT NULL := '76 225 508';
BEGIN
IF SUBSTR(v_telephone,1,1)='7'
DBMS_OUTPUT.PUT_LINE ('C''est un Fixe!')
ELSE
DBMS_OUTPUT.PUT_LINE ('C''est un Portable…');
END IF;
END;

Exemple 3.2

DECLARE
v_mention CHAR(2);
v_note NUMBER(4,2) := 9.8;
BEGIN
IF v_note >= 16 THEN
v_mention := 'TB';
ELSIF v_note >= 14 THEN
v_mention := 'B';
ELSIF v_note >= 12 THEN
v_mention := 'AB';
ELSIF v_note >= 10 THEN
v_mention := 'P';
ELSE
v_mention := 'R';

END IF;
END IF;
END IF;
END IF;
END IF;

DBMS_OUTPUT.PUT_LINE('La mention est ' || v_mention);


END;

Exercice 2
1. Réécrire l’exemple 3.2 en utilisant CASE.
2. Ecrire un bloc PL/SQL permettant de calculer la somme des 100 premiers entiers (boucle
tant que).
3. Réécrire la question en utilisant la boucle répéter
4. Ecrire un bloc PL/SQL permettant de chercher le numéro 9 dans une chaine de caractère
contenant le numéro d’un téléphone.

36-Mohamed Fadhel SAAD SGBD


Département Technologies de l’Informatique

Exercice 3
Ecrire le programme PL/SQL
 L’utilisateur saisit un nom d’employé
 Si cet employé n’a pas de travail défini, vous devez afficher le nom de l’employé suivi de n’a
pas de travail.
 Si cet employé est un manager vous devez lui attribuer 1000 dinars de commission et afficher
le nom de l’employé suivi de a 1000 dinars de commission
 Si cet employé est dans la table mais n’est pas manager, vous devez lui affecter 0 de
commission et afficher le nom de l’employé suivi de n’a pas de commission

Exercice 4
 Créer un bloc PL/SQL qui boucle pour chaque département (le numéro des départements va de 1 à
50) afin de modifier la commission de tous les employés. Ne pas valider (pas de commit).
Si le numéro de département est pair mettre la commission à 500 (même si elle l’est déjà), sinon
mettre à 300 pour les numéros de département impairs.
Annuler les modifications (rollback). 

SGBD Mohamed Fadhel SAAD-37


Département Technologies de l’Informatique

Atelier 4 
Les curseurs
Objectifs
Ecrire des blocs PL/SQL en utilisant les curseurs.

Pré-requis
Connaissance de Langage de définition et de manipulation de données en SQL.
Création des blocs simples PL/SQL.
Connaissance des structures de programmation PL/SQL (boucles, structures de
contrôle).

38-Mohamed Fadhel SAAD SGBD


Département Technologies de l’Informatique
Généralités
L’interaction avec Oracle consiste à accéder au contenu de la base de données et à le manipuler. Ce
traitement est réalisé par des commandes SQL. Deux méthodes sont utilisées : soit en mode autonome
à partir de l’outil SQL*Plus, soit à partir d’un bloc PL/SQL. Toute instruction du LMD (et seulement
du LMD) peut être écrite directement à différents endroits d’un programme PL/SQL. Pour traiter
cette instruction SQL, Oracle a besoin de créer une zone de mémoire connue sous le nom de "zone
privée de SQL", qui contient les informations nécessaires pour exploiter la commande SQL. Ces
informations comprennent le nombre de lignes traitées par l’instruction et un pointeur vers la
représentation analysée de l’instruction. L’accès à ces informations relatives se fait par un concept
appelé curseur.

Un curseur PL/SQL est une zone mémoire privée de SQL qui contient le résultat d’une requête. Le
curseur gère toutes les étapes du traitement de la requête.

Donc, on peut dire que toutes les requêtes sont associées à un curseur. Il existe deux types de curseurs :
Les curseurs implicites : Ils sont déclarés automatiquement chaque fois qu’une instruction SQL est
exécutée. L’utilisateur n’a aucune connaissance sur ces curseurs et il ne peut pas contrôler ou traiter
les informations contenues dans ces curseurs implicites. Ces types de curseurs ne sont pas définis dans
la section DECLARE.
Les curseurs explicites : Ils sont générés et gérés par le programmeur pour traiter un ordre  SELECT
qui ramène plusieurs lignes. Ces types de curseurs sont définis dans la section  DECLARE.

SGBD Mohamed Fadhel SAAD-39


Département Technologies de l’Informatique

Curseurs implicites
Le curseur implicite est un curseur de session qui est déclaré et géré implicitement par
PL/SQL.

Le serveur Oracle ouvre un curseur implicite chaque fois qu’une instruction est exécutée.
Cette instruction peut être :

 SELECT, qui doit alors ramener exactement une seule ligne.


 INSERT, DELETE ou UPDATE sans aucune contrainte sur le nombre de n-uplets
affectés.

Le programmeur ne peut pas contrôler un curseur implicite, mais il peut obtenir des
informations à partir de ses attributs qui peuvent être employés dans une section de
traitement ou d’exception. Les principaux attributs sont les suivants :

 L’attribut SQL%ISOPEN
SQL%ISOPEN retourne toujours FALSE, car un curseur implicite se ferme toujours
après l’exécution de l’instruction associée.
 L’attribut SQL%FOUND
SQL%FOUND retourne :
 NULL, si aucune instruction SELECT ou LMD n’a été exécutée.
 TRUE, si la dernière instruction LMD affecte au moins une ligne ou si une
instruction SELECT renvoie une ou plusieurs lignes.
 FALSE, sinon.

Curseur implicite : exemple 1

Déterminer si une instruction UPDATE affecte des lignes de la table PROJET.

-- curseur_implicite1.sql 
SET SERVEROUTPUT ON  
 
BEGIN 
-- modification des projets dont l’emplacement est PARIS  
  UPDATE PROJET 
  SET EMPLACEMENT=’BORDEAUX’ 
  WHERE EMPLACEMENT=’PARIS’; 
 
-- vérification des modifications  
  IF SQL%FOUND THEN 
     DBMS_OUTPUT.PUT_LINE(’Modification effectuée’); 
  ELSE 
     DBMS_OUTPUT.PUT_LINE(’Pas de modification’); 
  END IF; 
 
 ROLLBACK; 
END; 
/

40-Mohamed Fadhel SAAD SGBD


Département Technologies de l’Informatique
Résultat

Modification effectuée

 L’attribut SQL%NOTFOUND
SQL%NOTFOUND retourne :
 NULL, si aucune instruction SELECT ou LMD n’a été exécutée.
 FALSE, si la dernière instruction LMD affecte au moins une ligne ou si une
instruction SELECT renvoie une ou plusieurs lignes.
 TRUE, sinon.

L’attribut SQL%NOTFOUND n’est pas utile avec l’instruction SELECT INTO, parce que si


l’instruction ne retourne aucune ligne, alors une exception sera déclenchée
automatiquement. En outre, si l’instruction possède une fonction de regroupement, la
requête renvoie toujours un résultat.

Curseur implicite : exemple 2

Réécrire le bloc PL/SQL précédent avec l’attribut SQL%NOTFOUND.

-- curseur_implicite2.sql 
SET SERVEROUTPUT ON  
BEGIN 
-- modification des projets dont l’emplacement est PARIS  
  UPDATE PROJET 
  SET EMPLACEMENT=’BORDEAUX’ 
  WHERE EMPLACEMENT=’PARIS’; 
 
-- vérification si des modifications sont effectuées  
  IF SQL%NOTFOUND THEN 
     DBMS_OUTPUT.PUT_LINE(’Pas de modification’);  
  ELSE 
     DBMS_OUTPUT.PUT_LINE(’Modification effectuée’); 
  END IF; 
 ROLLBACK; 
END; 
/

Résultat

Modification effectuée

 L’attribut SQL%ROWCOUNT
SQL%ROWCOUNT retourne le nombre de lignes renvoyées par une
instruction SELECT ou affectées par la dernière instruction LMD.
Si aucune instruction SELECT ou LMD n’a été exécutée,  SQL%ROWCOUNT retourne la
valeur NULL.
 Remarque
Si un serveur est Oracle 12c et son client est Oracle 11g2 (ou versions antérieures), le
nombre maximum que SQL%ROWCOUNT retourne est 4 294 967 295.

SGBD Mohamed Fadhel SAAD-41


Département Technologies de l’Informatique

Curseur implicite : exemple 3

Utiliser SQL%ROWCOUNT pour déterminer le nombre de lignes qui ont été supprimées de la


table PROJET.

-- curseur_implicite3.sql 
SET SERVEROUTPUT ON  
 
BEGIN 
-- Suppression des lignes de la table TRAVAILLER  
  DELETE FROM TRAVAILLER; 
  
-- le nombre de lignes supprimées   
  DBMS_OUTPUT.PUT_LINE(’Le nombre de lignes supprimées de la table  
TRAVAILLER est  ’|| SQL%ROWCOUNT); 
 
 ROLLBACK; 
END; 
/

Résultat

Le nombre de lignes supprimées de la table TRAVAILLER est 11

42-Mohamed Fadhel SAAD SGBD


Département Technologies de l’Informatique

Curseurs explicites
1. Contrôle des curseurs explicites

Un curseur explicite est un curseur de session que le programmeur construit et gère.


Le curseur est déclaré et défini dans la partie déclarative, en lui donnant un nom et
en l’associant à une requête (en général, la requête renvoie plusieurs lignes).
Ensuite, il est ouvert dans la partie exécutable et le curseur peut être parcouru en
chargeant les lignes une par une dans une variable locale. Finalement, le curseur
sera fermé.

L’avantage de l’utilisation du curseur explicite par rapport au curseur implicite est


que le curseur explicite donne au programmeur un contrôle plus
« programmatique ». En outre, les curseurs implicites SELECT...INTO (ramène une
seule ligne) sont moins efficaces que les curseurs explicites car ces derniers ne
permettent pas de traiter un ensemble de lignes en même temps.

Le processus de travail avec un curseur explicite se compose des étapes suivantes :

1. Déclarer et définir le curseur ; cela initialise le curseur dans la mémoire.

2. Ouvrir le curseur.

3. Charger la ligne courante dans des variables.

4. Fermer le curseur ; le curseur déclaré, ouvert et récupéré doit être fermé pour
libérer la mémoire allouée.

a. Déclaration et définition du curseur

Vous pouvez déclarer un curseur explicite d’abord, puis le définir plus tard ou le
déclarer et le définir en même temps.

La déclaration du curseur se fait en utilisant l’instruction CURSOR et en le nommant.

Un curseur se déclare dans la section DECLARE :

DECLARE 
  CURSOR nom_curseur  RETURN return_type;

La définition du curseur a cette syntaxe :

DECLARE 
  CURSOR nom_curseur IS requête_select;

La requête SELECT peut contenir toutes les commandes SQL. Si la requête du


curseur possède des expressions ou des fonctions dans la clause SELECT, ces
dernières doivent comporter des alias pour pouvoir être référencées.  

 Remarque
Ne pas inclure la clause INTO  dans la déclaration du curseur, elle intervient plus tard
dans la commande FETCH.

SGBD Mohamed Fadhel SAAD-43


Département Technologies de l’Informatique

Définition d’un curseur : exemple

Déclaration et définition des curseurs explicites.

-- definition_cur.sql 
DECLARE 
-- déclaration c1 
  CURSOR c1 RETURN PROJET%ROWTYPE;  
 
-- déclaration et définition c2 
  CURSOR c2 IS SELECT *  
               FROM EMPLOYE 
               WHERE SALAIRE > 4000; 
 
-- définition c1 
  CURSOR c1 RETURN PROJET%ROWTYPE IS SELECT *  
                                     FROM PROJET; 
-- déclaration c3 
  CURSOR c3 RETURN TRAVAILLER%ROWTYPE; 
 
-- définition c3 
  CURSOR c3 IS SELECT *  
               FROM TRAVAILLER 
               WHERE MATRICULE = 780; 
 
BEGIN 
 
  NULL 
 
END; 
/

b. Ouverture et fermeture du curseur

Après la déclaration et la définition d’un curseur explicite dans la partie déclarative,


vous pouvez l’ouvrir dans la partie exécutable, et cela en utilisant la syntaxe
suivante.

OPEN nom_curseur;

La syntaxe utilisée pour la fermeture d’un curseur est :

CLOSE nom_curseur;

 Remarque
Une base de données a un nombre limité de curseurs ouverts pour toutes les
sessions. Si vous dépassez ce nombre, vous recevez un message d’erreurs.

c. Accès aux données d’un curseur

Une fois le curseur est ouvert, il contient toutes les lignes du résultat de la requête.
On les récupère une par une en utilisant le mot-clé FETCH. La syntaxe de base d’une
instruction FETCH qui renvoie une ligne est :

44-Mohamed Fadhel SAAD SGBD


Département Technologies de l’Informatique

FETCH nom_curseur INTO variable1,variable2,...;

 Remarque
Le curseur doit impérativement être ouvert, avant l’utilisation de l’instruction FETCH.

Curseur explicite : exemple 1

Écrire un bloc PL/SQL qui permet d’afficher les villes où a travaillé l’employé ayant le
matricule 7600.

-- curseur_explicite1.sql  
SET SERVEROUTPUT ON 
 
DECLARE 
-- déclaration du curseur   CURSOR c IS SELECT DISTINCT EMPLACEMENT 
              FROM TRAVAILLER T, PROJET P 
              WHERE T.NUMPROJ = P.NUMPROJ  
              AND MATRICULE=7600 
              ORDER BY EMPLACEMENT; 
  ville PROJET.EMPLACEMENT%TYPE; 
  nbre_ligne INTEGER; 
 
BEGIN 
-- nombre de lignes du curseur 
  SELECT COUNT(DISTINCT EMPLACEMENT) INTO nbre_ligne 
  FROM TRAVAILLER T, PROJET  
  WHERE T.NUMPROJ = P.NUMPROJ  
  AND MATRICULE=7600; 
 
-- ouverture du curseur 
  OPEN c; 
 
-- lecture du curseur 
  DBMS_OUTPUT.PUT_LINE(’L’’employé de matricule 7600 a travaillé  
dans les villes et pays :’); 
  FOR i IN 1..nbre_ligne LOOP 
     FETCH c INTO ville; 
     DBMS_OUTPUT.PUT_LINE(’-- ’ || ville); 
  END LOOP; 
 
-- fermeture du curseur 
  CLOSE c; 
 
END; 
/

Résultat

L’employé de matricule 7600 a travaillé dans les villes et pays :

-- BENIN  
-- HAITI  
-- MADAGASCAR  

SGBD Mohamed Fadhel SAAD-45


Département Technologies de l’Informatique

-- PARIS
 Remarque
De l’ouverture à la fermeture d’un curseur, les lignes renvoyées par le curseur ne
changent pas et ne tiendront pas compte d’éventuelles modifications, insertions et
suppressions effectuées après l’ouverture du curseur.  

2. Attributs d’un curseur explicite

Pour toute manipulation d’un curseur, le moteur SQL envoie une information appelée
statut, qui nous indique si la requête a été exécutée correctement ou non. Comme
avec les curseurs implicites, cette information est disponible par l’intermédiaire de
quatre attributs. Ces attributs sont :

Attribut Type Valeur Explication


TRUE Si le curseur est ouvert.
%ISOPEN BOOLEAN
FALSE Si le curseur est fermé ou non encore ouvert.
TRUE Si le dernier FETCH ne trouve plus une ligne à
ramener.
FALSE Si le dernier FETCH ne trouve plus une ligne à
%FOUND BOOLEAN
ramener.
NULL Avant le premier FETCH ; c’est-à-dire curseur
ouvert.
TRUE Si le dernier FETCH ne trouve plus une ligne à
ramener.

%NOTFOUND BOOLEAN FALSE Si le dernier FETCH ramène une ligne.

NULL Avant le premier FETCH ; c’est-à-dire curseur


ouvert.

Entier Compteur qui s’incrémente après chaque ligne


%ROWCOUNT NUMBER lue par FETCH.

Zéro Après OPEN et avant le premier FETCH.

Pour consulter un attribut d’un curseur donné, on utilise la syntaxe suivante :

nom_curseur%ATTRIBUT;

Le tableau suivant présente les différentes valeurs possibles des attributs :

%ISOPEN %FOUND %NOTFOUND %ROWCOUNT

avan FALSE exception exception exception


OPEN t

après TRUE NULL NULL 0

46-Mohamed Fadhel SAAD SGBD


Département Technologies de l’Informatique

avan TRUE FALSE TRUE nombre de lignes lues


CLOSE t

après FALSE exception exception 0

avan TRUE NULL NULL 0


premier t
FETCH
après TRUE TRUE FALSE 1

FETCH avan TRUE TRUE FALSE nombre de lignes lues


suivants t avant FETCH

après TRUE TRUE FALSE nombre de lignes lues


avant FETCH +1

avan TRUE TRUE TRUE nombre de lignes de la


t requête-1
dernier
FETCH
après TRUE FALSE FALSE nombre de lignes de la
requête

Curseur explicite : exemple 2

Exemple d’utilisation de l’attribut %ISOPEN.

-- curseur_explicite2.sql 
DECLARE 
-- déclaration du curseur 
  CURSOR c IS SELECT DISTINCT EMPLACEMENT 
              FROM TRAVAILLER T, PROJET P 
              WHERE T.NUMPROJ = P.NUMPROJ  
              AND MATRICULE=7600 
              ORDER BY EMPLACEMENT; 
  ville PROJET.EMPLACEMENT%TYPE;    
 
BEGIN 
 
-- ISOPEN  
  IF NOT c%ISOPEN THEN 
     OPEN c; 

  END IF; 
  FETCH c INTO ville; 
  IF c%ISOPEN THEN 
     CLOSE c; 
  END IF; 
 
END; 

Curseur explicite : exemple 3

Exemple d’utilisation de l’attribut %FOUND.

-- curseur_explicite3.sql 

SGBD Mohamed Fadhel SAAD-47


Département Technologies de l’Informatique

SET SERVEROUTPUT ON 


 
DECLARE 
-- déclaration du curseur 
  CURSOR c IS SELECT ENOM, SALAIRE  
              FROM EMPLOYE 
              WHERE ROWNUM < 7 
              ORDER BY ENOM; 
  vnom EMPLOYE.ENOM%TYPE; 
  vsalaire EMPLOYE.SALAIRE%TYPE; 
 
BEGIN 
 
  OPEN c; 
  LOOP 
     FETCH c INTO vnom, vsalaire; 
     IF c%FOUND THEN -- fetch retourne une ligne 
       DBMS_OUTPUT.PUT_LINE 

      (’Nom = ’ || vnom || ’, SALAIRE = ’ || vsalaire); 


     ELSE -- fetch ne retourne aucune ligne 
       EXIT; 
    END IF; 
  END LOOP; 

END; 
/

Résultat

Nom = BLAKE, SALAIRE = 2850 


Nom = CLARK, SALAIRE = 2450 
Nom = JONES, SALAIRE = 2975 
Nom = LOLA, SALAIRE = 1750 
Nom = SCOTT, SALAIRE = 3000 
Nom = THOMAS, SALAIRE = 5000

Curseur explicite : exemple 4

Exemple d’utilisation de l’attribut %NOTFOUND.

--curseur_explicite4.sql 
SET SERVEROUTPUT ON 
 
DECLARE 
-- déclaration du curseur 
  CURSOR c IS SELECT ENOM, SALAIRE  
              FROM EMPLOYE 
              WHERE ROWNUM < 7 
              ORDER BY ENOM; 
  vnom EMPLOYE.ENOM%TYPE; 

48-Mohamed Fadhel SAAD SGBD


Département Technologies de l’Informatique

  vsalaire EMPLOYE.SALAIRE%TYPE; 
 
BEGIN 
 
  OPEN c; 
  LOOP 
     FETCH c INTO vnom, vsalaire; 
     IF c%FOUND THEN -- fetch retourne une ligne 
       DBMS_OUTPUT.PUT_LINE 
      (’Nom = ’ || vnom || ’, SALAIRE = ’ || vsalaire); 
     ELSE -- fetch ne retourne aucune ligne 
       EXIT; 
    END IF; 
  END LOOP; 
 
END; 
/

Résultat

Nom = BLAKE, SALAIRE = 2850 


Nom = CLARK, SALAIRE = 2450 
Nom = JONES, SALAIRE = 2975 
Nom = LOLA, SALAIRE = 1750 
Nom = SCOTT, SALAIRE = 3000 
Nom = THOMAS, SALAIRE = 5000

Curseur explicite : exemple   5

Exemple d’utilisation de l’attribut %ROWCOUNT.

-- curseur_explicite5.sql 
SET SERVEROUTPUT ON 
 
DECLARE 
-- déclaration du curseur 
  CURSOR c IS SELECT ENOM  
              FROM EMPLOYE 
              WHERE ROWNUM < 7 
              ORDER BY ENOM; 
  vnom EMPLOYE.ENOM%TYPE; 
 
BEGIN 
 
  OPEN c; 
  LOOP 
     FETCH c INTO vnom; 
  EXIT WHEN c%NOTFOUND OR c%NOTFOUND IS NULL; 
     DBMS_OUTPUT.PUT_LINE(c%ROWCOUNT || ’. ’ || vnom); 
     IF c%ROWCOUNT = 3 THEN 
        DBMS_OUTPUT.PUT_LINE(’--- Fetch 3 lignes ---’); 
     END IF; 

SGBD Mohamed Fadhel SAAD-49


Département Technologies de l’Informatique

  END LOOP; 
  CLOSE c; 
 
END; 
/

Résultat

1. BLAKE 
2. CLARK 
3. JONES 
--- Fetch 3 lignes  
4. LOLA 
5. SCOTT 
6. THOMAS
 Remarque
En cas d’utilisation de %ROWCOUNT, ajouter un test avec %NOTFOUND  pour détecter
l’absence de lignes, car l’attribut %ROWCOUNT  ne s’incrémente pas si  FETCH ne
ramène pas de ligne.

3. Curseurs et enregistrements

La déclaration d’un enregistrement basé sur un curseur se fait de la façon suivante :

nom_enregistrement nom_curseur%ROWTYPE;

L’extraction de lignes d’un curseur est effectuée par l’instruction :

FETCH nom_curseur INTO nom_enregistrement;

L’accès aux valeurs des champs de l’enregistrement se fait par la notation pointée comme le
montre l’exemple ci-dessous.

Curseur explicite : exemple 6

Écrire un bloc PL/SQL qui permet d’afficher les noms et les salaires des employés ayant la
fonction ’MANAGER’.

-- curseur_explicite6.sql 
SET SERVEROUTPUT ON 
 
DECLARE  
-- déclaration du curseur 
  CURSOR emp_curseur IS SELECT ENOM, SALAIRE  
                FROM EMPLOYE  
                WHERE FONCTION = ’MANAGER’; 
-- déclaration d’une variable enregistrement 
  rec1 emp_curseur%ROWTYPE; 

50-Mohamed Fadhel SAAD SGBD


Département Technologies de l’Informatique

BEGIN 
-- chargement du curseur  
  OPEN emp_curseur;  
  LOOP  
-- accès aux éléments du curseur 
     FETCH emp_curseur INTO rec1;  
  EXIT WHEN emp_curseur%NOTFOUND; 
     DBMS_OUTPUT.PUT_LINE 
     ( rec1.enom||’ a le salaire ’|| rec1.salaire); 
  END LOOP; 
  CLOSE emp_curseur; 
 
END; 
/

Résultat

BLAKE a le salaire 2850  

CLARK a le salaire 2450  

JONES a le salaire 2975  

4. Curseurs FOR UPDATE

Jusqu’à présent, nous n’avons utilisé les curseurs que pour consulter et afficher des
informations de la base de données. Lorsqu’on lance le curseur, aucun verrou n’est
mis sur les lignes. Mais il peut être intéressant de verrouiller des lignes avant de
modifier ou supprimer celles-ci. Pour ce type de verrous, PL/SQL offre la clause FOR
UPDATE dans la déclaration du curseur et l’on appelle ceci « curseur FOR UPDATE ».

La syntaxe de déclaration d’un curseur est :

DECLARE 
  CURSOR nom_curseur IS requête_select  
                        FOR UPDATE 
                        [OF nom_colonne [,...]] 
                        [{NOWAIT | WAIT nbre_secondes}];

Où :

 nom_colonne désigne une ou plusieurs colonnes sur lesquelles est appliquée la


clause FOR UPDATE.
 NOWAIT signifie qu’il ne faut pas attendre le programme si les lignes
demandées sont verrouillées par une autre session.
 WAIT nbre_secondes indique que le programme attend
nbre_secondes secondes avant que les enregistrements ne soient
déverrouillés.

SELECT...FOR UPDATE permet de baser une mise à jour sur les valeurs existant
dans les lignes du curseur. Oracle verrouillera ces lignes à l’ouverture du curseur. Il
garantit qu’aucun autre utilisateur ne peut modifier ces valeurs avant que le
programme ne les mette à jour.

SGBD Mohamed Fadhel SAAD-51


Département Technologies de l’Informatique

Le serveur Oracle libère le verrou à la fin de la transaction. Donc, vous ne pouvez


pas faire l’opération de validation (COMMIT) ou d’annulation (ROLLBACK) entre
deux FETCH ou avant la fermeture du curseur.

Il est souvent intéressant de faire un DELETE ou un UPDATE avec la clause WHERE


CURRENT OF nom_curseur : cette clause permet de référencer la ligne du curseur,
on n’a pas besoin d’une condition WHERE sur la valeur d’un champ.

Curseur explicite de mise à jour : exemple 1

Écrire un bloc PL/SQL qui utilise le curseur FOR UPDATE pour :

 augmenter le salaire des managers de 20 % ;


 augmenter le salaire des analystes de 30 % ;
 affecter une commission de 10 % du salaire aux secrétaires.
-- curseur_maj1.sql 
DECLARE 
-- déclaration du curseur 

  CURSOR emp_curseur IS 


                       SELECT * 
                       FROM EMPLOYE 
                       FOR UPDATE;  
-- déclaration d’une variable enregistrement 
 rec emp_curseur%ROWTYPE; 
 
BEGIN 
 
-- chargement du curseur  
  OPEN emp_curseur;  
  LOOP 
-- accès aux éléments du curseur 
     FETCH emp_curseur INTO rec;  
  EXIT WHEN emp_curseur%NOTFOUND; 
-- mise à jour de la table employe 
     IF rec.fonction= ’MANAGER’ THEN 
        UPDATE EMPLOYE 
        SET SALAIRE = SALAIRE * 1.2 
        WHERE CURRENT OF emp_curseur; 
     END IF; 
     IF rec.fonction= ’ANALYSTE’ THEN 
        UPDATE EMPLOYE 
        SET SALAIRE = SALAIRE * 1.3 
        WHERE CURRENT OF emp_curseur; 
     END IF;      IF rec.fonction= ’Secrétaire’ THEN 
       UPDATE EMPLOYE 
       SET COMMISSION = SALAIRE * 0.1 
       WHERE CURRENT OF emp_curseur; 
     END IF; 
 
  END LOOP; 
END; 
/

52-Mohamed Fadhel SAAD SGBD


Département Technologies de l’Informatique

 Remarque
On ne peut pas utiliser la commande  FETCH sur un curseur  FOR UPDATE, après avoir
fait l’opération de validation (COMMIT) ou d’annulation (ROLLBACK). Le pointage dans
le curseur est perdu.

5. Curseurs paramétrés

Dans tous les curseurs précédents, les ordres SQL étaient fixes et les curseurs sont
exécutés avec une seule valeur. Or, il est possible de spécifier un curseur avec des
paramètres dans lesquels on passe des valeurs.

Avec le curseur paramétré, on peut réutiliser un même curseur dans le même bloc
avec des valeurs différentes.

CURSOR nom_curseur(nom_parametre type_donnees , ...) 


   IS requête_select;

Curseur explicite paramétré : exemple 1

Écrire un bloc PL/SQL qui permet d’afficher les noms de deux employés dont les
matricules sont donnés, en utilisant un curseur paramétré.

-- curseur_parametre1.sql 
SET SERVEROUTPUT ON 
 
DECLARE 
-- déclaration du curseur 
  CURSOR emp_curseur( par_num EMPLOYE.MATRICULE%TYPE )IS 
                      Select MATRICULE, ENOM, FONCTION 
                      From EMPLOYE  
                      Where MATRICULE = par_num; 
-- variables  
  vmat EMPLOYE.MATRICULE%TYPE; 
  vnom EMPLOYE.ENOM%TYPE; 
  vfonction EMPLOYE.FONCTION%TYPE;  
  
Begin  
 
-- ouverture du curseur avec passage du paramètre effectif 7800 
  OPEN emp_curseur(7800);  
  FETCH emp_curseur INTO vmat, vnom, vfonction; 
  IF  emp_curseur%FOUND THEN   
      DBMS_OUTPUT.PUT_LINE 
     (’Employé ’ || TO_CHAR(vmat) || ’ ’ || vnom ); 
  ELSE 
      DBMS_OUTPUT.PUT_LINE 
    (’Employé ’ || TO_CHAR(vmat) || ’ n’’existe pas ’); 
  END IF; 
-- fermeture du curseur 
  Close emp_curseur; 
 
-- ouverture du curseur avec passage du paramètre effectif 7600 
  OPEN emp_curseur(7600);  
  FETCH emp_curseur INTO vmat, vnom, vfonction; 

SGBD Mohamed Fadhel SAAD-53


Département Technologies de l’Informatique

  IF  emp_curseur%FOUND THEN   
      DBMS_OUTPUT.PUT_LINE 
     (’Employé ’ || TO_CHAR(vmat) || ’ ’ || vnom ); 
  ELSE 
      DBMS_OUTPUT.PUT_LINE 
     (’Employé ’ || TO_CHAR(vmat) || ’ n’’existe pas ’); 
  END IF; 
-- fermeture du curseur 
  Close emp_curseur; 
 
END;   
/

Résultat

Employé 7800 THOMAS  


Employé 7600 BLAKE  

Lorsque vous créez un curseur explicite avec les paramètres formels, vous pouvez
spécifier des valeurs par défaut pour eux. Quand un paramètre formel a une valeur
par défaut, le paramètre effectif correspondant est facultatif. Si vous ouvrez le
curseur sans indiquer le paramètre effectif, le paramètre formel a sa valeur défaut.

Curseur explicite paramétré : exemple 2

Écrire un bloc PL/SQL qui permet d’afficher les noms et les salaires des employés
qui ont des salaires supérieurs à une valeur donnée (paramètre du curseur) et qui
sont recrutés après une date donnée (paramètre du curseur avec une valeur par
défaut).

-- curseur_parametre2.sql 
SET SERVEROUTPUT ON 
 
DECLARE 
  CURSOR c( max_sal NUMBER, date_rec DATE DEFAULT   
             TO_DATE(’20-10-1990’,’dd-mm-yyyy’)) IS 
                         SELECT * 
                         FROM EMPLOYE 
                         WHERE SALAIRE > max_sal 
                         AND DATEREC > date_rec 
                         ORDER BY SALAIRE; 
  enr c%ROWTYPE; 
 
BEGIN 
 
  OPEN c(2000); 
  LOOP 
     FETCH c INTO enr; 
  EXIT WHEN c%NOTFOUND; 
     DBMS_OUTPUT.PUT_LINE(enr.enom|| ’ a le salaire ’ ||   
     enr.salaire ); 
  END LOOP; 
CLOSE c; 
 

54-Mohamed Fadhel SAAD SGBD


Département Technologies de l’Informatique

END; 
/

Résultat

SCOTT a le salaire 3000        

6. Boucle FOR avec curseur

Il existe plusieurs opérations propres aux curseurs. L’opération principale est le parcours d’un
curseur. Vous pouvez utiliser les différents types de structures répétitives. Il peut être
intéressant d’utiliser une boucle plus simple pour l’exploitation d’un curseur.

Oracle propose une variante de la boucle FOR qui traite les lignes dans un curseur explicite. Il y
aura une gestion automatique de l’ouverture, de la lecture, du test de sortie et de la fermeture
du curseur.

La syntaxe pour l’utilisation d’un curseur dans la boucle FOR est :

FOR nom_enregistrement IN nom_curseur(parametre, ...) 


LOOP 
... 
END LOOP;

Utilisation de FOR avec curseur : exemple 1

Écrire un bloc PL/SQL qui permet d’afficher les matricules et les noms des employés d’un
département donné (paramètre du curseur).

-- pour_curseur1.sql 
SET SERVEROUTPUT ON 
 
DECLARE 
-- déclaration du curseur 
  CURSOR personnel( vdnom varchar2 ) 
        IS SELECT MATRICULE, ENOM 
           FROM EMPLOYE, DEPARTEMENT 
           WHERE DNOM = vdnom 
           AND EMPLOYE.NUMDEPT = DEPARTEMENT.NUMDEPT; 
 
BEGIN 
 
-- parcours du curseur  
  DBMS_OUTPUT.PUT_LINE(’Les personnels du département finance  sont : ’); 
  FOR ligne IN personnel(’FINANCE’)LOOP 
      DBMS_OUTPUT.PUT_LINE(’Matricule : ’ || ligne.matricule 
 || ’ -- Nom : ’ || ligne.enom); 
  END LOOP; 
END; 
/

Résultat

Les personnels du département finance sont : 

Matricule : 7566 -- Nom : JONES 

SGBD Mohamed Fadhel SAAD-55


Département Technologies de l’Informatique

Matricule : 7780 -- Nom : CLARK

La commande SELECT est une requête considérée comme un curseur local anonyme et de ce


fait, n’a pas d’attributs accessibles. Oracle offre là, la possibilité de manipuler une requête SQL
sans faire la déclaration d’un curseur explicite.

Utilisation FOR curseur : exemple 2

Écrire un bloc PL/SQL qui permet d’afficher les matricules et les noms des employés du
département administratif, sans qu’on utilise la déclaration d’un curseur.

-- pour_curseur2.sql 

SET SERVEROUTPUT ON 


 
-- pas de déclaration du curseur 
BEGIN 
 
-- parcours du curseur  
DBMS_OUTPUT.PUT_LINE(’Les personnels du département  
administratif  sont : ’); 
  FOR ligne IN  
      ( SELECT MATRICULE, ENOM 
         FROM EMPLOYE, DEPARTEMENT 
         WHERE DNOM = ’ADMINISTRATIF’ 
         AND EMPLOYE.NUMDEPT = DEPARTEMENT.NUMDEPT) 
  LOOP 
      DBMS_OUTPUT.PUT_LINE(’Matricule :’ || ligne.matricule 
 || ’ -- Nom : ’ || ligne.enom); 
  END LOOP; 
 
END; 
/

Résultat

Les personnels du département administratif sont :

Matricule : 7902 -- Nom : LOLA 

Matricule : 7800 -- Nom : THOMAS

56-Mohamed Fadhel SAAD SGBD


Département Technologies de l’Informatique

Série d’exercices

Exercice 1
Exécuter les scripts suivants, détecter les erreurs s’ils existent et les corrigent. Ensuite expliquer ce
qu’il fait.

Exemple 4.1

DECLARE
v_empno employe.empno%TYPE;
v_nom employe.enom%TYPE;
CURSOR emp_cursor IS
SELECT empno, enom
FROM employe;
BEGIN
OPEN emp_cursor;
LOOP
FETCH emp_cursor INTO v_empno, v_nom;
EXIT WHEN emp_cursor%ROWCOUNT > 10 OR emp_cursor%NOTFOUND;
DBMS_OUTPUT.PUT_LINE (TO_CHAR(v_empno)||' '|| enom);
END LOOP;
CLOSE emp_cursor;
END;

Exercice 2
1. Ecrire un bloc anonyme PL/SQL qui permet d’afficher les noms des employés dont leur
salaire est supérieur à 500.
2. Modifier ce bloc en utilisant un curseur explicite avec comme paramètres le salaire des
employés.
3. Écrire un bloc anonyme PL/SQL qui permet d’afficher le nom, la fonction, le salaire et
numéro de département de la table employe
4. Ecrire bloc anonyme PL/SQL qui permet d’augmenter le salaire selon les critères suivants:

Salair Incrémentation
e
< 1200 8%
< 2500 12%
<4500 15%
Autre 20%
5. Ecrire un bloc PL/SQL qui permet d’afficher le nom, le salaire et le prime de rendement.
On suppose que la prime de rendement est 20% du salaire. En utilisant la boucle FOR.

SGBD Mohamed Fadhel SAAD-57


Département Technologies de l’Informatique

Atelier 5 
Les exceptions
Objectifs
Ecrire des blocs PL/SQL en utilisant les exceptions.

Pré-requis
Connaissance de Langage de définition et de manipulation de données en SQL.
Création des blocs simples PL/SQL.
Connaissance des structures de programmation PL/SQL (boucles, structures de
contrôle).
Connaissance des curseurs.

58-Mohamed Fadhel SAAD SGBD


Département Technologies de l’Informatique

Exercice 1
Exécuter les scripts suivants, détecter les erreurs s’ils existent et les corrigent. Ensuite expliquer ce
qu’il fait.
Exemple 5.1

DECLARE
num_tables NUMBER;
BEGIN
SELECT COUNT(*) INTO num_tables FROM USER_TABLES;
IF num_tables < 5 THEN
raise_application_error(' Moins de 5 tables ');
ELSE
NULL;
END IF;
END;

Exercice 2
Ecrire un bloc PL/SQL pour :
a) Entrer un numéro de département;
b) Afficher nom, la localité. S’il n’existe pas ce département, afficher un message d’erreur.
Conseil: Utiliser l’exception NO_DATA_FOUND

Exercice 3
Ecrire un bloc PL/SQL qui va interdire l’insertion des employés ayant moins de 200 dinars comme
salaire et ayant plus de 5000 dinars.

Exercice 4
Ecrire un bloc PL/SQL qui intercepte une suppression non réalisée d’un employé.

SGBD Mohamed Fadhel SAAD-59


Département Technologies de l’Informatique

Atelier 6 
Les sous-programmes
Objectifs
Ecrire des sous-programmes.

Pré-requis
Connaissance de Langage de définition et de manipulation de données en SQL.
Création des blocs PL/SQL.
Connaissance des curseurs.

60-Mohamed Fadhel SAAD SGBD


Département Technologies de l’Informatique

Exercice 1
Exécuter les scripts suivants, détecter les erreurs s’ils existent et les corrigent. Ensuite expliquer ce
qu’il fait.

Exemple 6.1

CREATE OR REPLACE FUNCTION FormatageDate(


p_date DATE,
p_separateur IN CHAR)
RETURN VARCHAR2
IS
BEGIN
RETURN(TO_CHAR(p_date,'dd')
|| p_separateur
|| TO_CHAR(p_date,'mm')
|| p_separateur
|| TO_CHAR(p_date,'yy'));
END;

Exemple 6.2

CREATE OR REPLACE FUNCTION test_function(


in_val1 IN NUMBER,
in_val2 IN VARCHAR2)
RETURN NUMBER
IS
BEGIN
RETURN (in_val1||' - '||in_val2);
END;

Exercice 2
1- Ecrire une procédure qui permet d’augmenter le salaire d’un employé.
2- Utiliser la procédure dans un bloc PL/SQL.
3- Ecrire une fonction qui permet de retourner le total salaire d’un département.
4- Ecrire une procédure qui permet d’augmenter le salaire en ajoutant un bonus (taux) de la
commission au salaire.

Exercice 3
1- Ecrire une fonction récursive retournant bn, avec n entier positif ou nul.
2- Améliorer la fonction précédente en utilisant le fait que
bn = (b2)n/2
si n est pair.
3- Ecrire une procédure qui fait la conversion d’une somme en dinars en une somme en euro.

SGBD Mohamed Fadhel SAAD-61


Département Technologies de l’Informatique

Atelier 7 
Les déclencheurs
Objectifs
Créer et utiliser les différents types de triggers.

Pré-requis
Connaissance des concepts base de données, modèle relationnel et contraintes
d’intégrités.
Connaissance de Langage de définition et de manipulation de données en SQL.
Connaissance des principes et techniques de programmation en PL/SQL

62-Mohamed Fadhel SAAD SGBD


Département Technologies de l’Informatique

Exercice 1
Saisir le script de la base de données suivant:
DROP TABLE RESULTAT;
DROP TABLE EXAMEN;
DROP TABLE PREREQUIS;
DROP TABLE INSCRIPTION;
DROP TABLE MODULE;
DROP TABLE ETUDIANT;
CREATE TABLE ETUDIANT
( numEtud number,
nom varchar2(40),
prenom varchar2(40),
datenaiss date,
civilite varchar2(4),
patronyme varchar2(40),
numsecu varchar2 (15) NOT NULL);

CREATE TABLE MODULE


( codMod number,
nomMod varchar2(15),
effecMax number DEFAULT 30);

CREATE TABLE EXAMEN


( codMod number,
codExam number,
dateExam date);

CREATE TABLE INSCRIPTION


( numEtud number,
codMod number,
dateInsc date default sysdate);

CREATE TABLE PREREQUIS


( codMod number,
codModPrereq number,
noteMin number(4,2) NOT NULL);

CREATE TABLE RESULTAT


( codMod number,
codExam number,
numEtud number,
note number(4,2));

ALTER TABLE ETUDIANT ADD


CONSTRAINT pk_etudiant
PRIMARY KEY (numEtud);
ALTER TABLE MODULE ADD
CONSTRAINT pk_module
PRIMARY KEY (codMod);
ALTER TABLE EXAMEN ADD
CONSTRAINT pk_examen
PRIMARY KEY (codMod, codExam);
ALTER TABLE PREREQUIS ADD
CONSTRAINT pk_prerequis
PRIMARY KEY (codMod, codModPrereq);
ALTER TABLE INSCRIPTION ADD
CONSTRAINT pk_inscription
PRIMARY KEY (codMod, numEtud);
ALTER TABLE RESULTAT ADD
CONSTRAINT pk_resultat

SGBD Mohamed Fadhel SAAD-63


Département Technologies de l’Informatique

PRIMARY KEY (codMod, numEtud, codExam);


ALTER TABLE INSCRIPTION ADD
(CONSTRAINT fk_inscription _etudiant FOREIGN KEY (numEtud)
REFERENCES ETUDIANT(numEtud),
CONSTRAINT fk_ inscription_module FOREIGN KEY (codMod)
REFERENCES MODULE (codMod));
ALTER TABLE PREREQUIS ADD
(CONSTRAINT fk_prerequis_codmod FOREIGN KEY (codMod)
REFERENCES MODULE (codMod),
CONSTRAINT fk_prerequis _codmodprereq FOREIGN KEY
(codModPrereq )
REFERENCES MODULE (codMod));
ALTER TABLE EXAMEN ADD
CONSTRAINT fk_examen FOREIGN KEY (codMod)
REFERENCES MODULE (codMod);
ALTER TABLE RESULTAT ADD
CONSTRAINT fk_resultat_examen FOREIGN KEY (codMod, codExam)
REFERENCES EXAMEN (codMod, codExam),
CONSTRAINT fk_resultat_inscription FOREIGN KEY (codMod,
numEtud)
REFERENCES INSCRIPTION(codMod, numEtud));
ALTER TABLE ETUDIANT ADD
(CONSTRAINT ck _ civilite CHECK (civilite IN ('Mr' , 'Mme',
'Mlle')));

Implémentez les contraintes suivantes:


1. Il ne doit pas être possible de modifier la note min dans la table prerequis.
2. Dans un module, il ne doit pas y avoir plus de effecMax élèves inscrits.
3. On ne peut créer un examen pour un module que s'il y a des élèves inscrits dans ce module.
4. Un élève ne peut passer un examen que si sa date d'inscription est antérieure _a la date de
l'examen.
5. Il ne doit pas y avoir de circuit dans la table prerequis.
6. Un élève s'inscrivant à un module doit avoir eu au moins la note min à tous les modules Pré-
requis.
7. Ajouter dans étudiant un champ moyenne, celui-ci contiendra la moyenne de chaque étudiant s'il
a passé les examens de tous les modules dans lesquels il est inscrit.
8. Revenez sur la première contrainte : il ne doit être possible de modifier une note min dans la table
prerequis que s'il n'existe pas d’élève dont une inscription serait invalidée.
9. Il ne doit être possible de modifier effecMax que si des étudiants ne se retrouvent pas avec une
inscription invalidée.

64-Mohamed Fadhel SAAD SGBD


Département Technologies de l’Informatique

Correction des ateliers 1 

SGBD Mohamed Fadhel SAAD-65


Département Technologies de l’Informatique

Atelier 1 
Exercice 1
1-
CREATE TABLE departement
( numdept INTEGER,
dnom VARCHAR2(40),
localite VARCHAR2(30),
CONSTRAINT pk_departement PRIMARY KEY(numdept)
);

2-

CREATE TABLE employe


(empno INTEGER,
enom VARCHAR2(40),
fonction VARCHAR2(30),
daterect DATE,
salaire NUMBER(10,3),
commission NUMBER(10,3),
numdept INTEGER,
CONSTRAINT pk_employe PRIMARY KEY(empno),
CONSTRAINT ck_salaire CHECK (salaire > 0),
CONSTRAINT ck_commission CHECK (commission > 0),
CONSTRAINT fk_dept_emp FOREIGN KEY(numdept)REFERENCES
departement(numdept)
);
.3-
INSERT INTO departement
values(10,’Financier’,’Tunis’);
INSERT INTO departement
values(20,’Informatique’,’Gafsa’);
INSERT INTO departement
values(30,’Commercial’,’Tozeur’);
INSERT INTO departement
values(40,’Recherche’,’Sfax’);
INSERT INTO employe
values(1000,’Mohamed Tlili’,’Ouvrier’, '17-12-1980', 350,NULL, 20);
INSERT INTO employe
values(2000,’Samira Othmani’,’Vendeur’, '24-09-2000', 700,50, 30);
INSERT INTO employe
values(2300,’Taher Hmidi’,’ Vendeur’, '13-09-1999', 850,70, 30);
INSERT INTO employe
values(1400,’Amira Sfaxi’,’Ouvrier’, '19-01-2005', 450,NULL, 10);
INSERT INTO employe
values(1170,’Sonia Amine’,’Chercheur’, '22-07-2008', 1500,500, 40);
INSERT INTO employe
values(2190,’Salah Mohamed’,’Ouvrier’, '12-12-1985', 400,NULL, 40);
INSERT INTO employe
values(1180,’Amir Touhami’,’Directeur’, '20-11-1987', 2000,600, 10);
INSERT INTO employe
values(1320,’Amina Salem’,’Chercheur’, '17-02-1989', 1800,400, 40);
INSERT INTO employe
values(2450,’Ahmed Saad’,’PDG’, '04-05-2010', 4500,NULL, 10);

66-Mohamed Fadhel SAAD SGBD


Département Technologies de l’Informatique

4-
UPDATE employe
SET salaire=salaire*1.1;
5-
UPDATE employe
SET salaire=salaire*1.5
WHERE numdept = ( SELECT numdept
FROM departement
WHERE dnom=’Recherche’);
6-
UPDATE departement
SET dnom= ‘Comptabilité-finance’
WHERE dnom= ‘Finance’
7-
UPDATE employe
SET commission= ( SELECT AVG(commission)
FROM employe)
WHERE commission IS NULL
AND daterect <=’01-01-1982’;
8-
DELETE FROM employe
WHERE function =’PDG’;
9-
UPDATE employe
SET function=’PDG’
WHERE empne=1320;
10-
COMMIT;

Exercice 2
1-
SELECT enom,salaire,commission, salaire+commission salaire_global
FROM employe
WHERE fonction=’Vendeur’;

2-
SELECT enom
OM employe
WHERE fonction=’Vendeur’
ORDER BY DESC salaire;
3-
SELECT enom
FROM employe
WHERE fonction=’Vendeur’
AND commission<=0.25*salaire;
4-
SELECT COUNT(*)
FROM employe
WHERE numdept=10;
5-
SELECT COUNT(*)
FROM employe
WHERE commission IS NOT NULL;
6-
SELECT COUNT(DISTINCT fonction)
FROM employe;

SGBD Mohamed Fadhel SAAD-67


Département Technologies de l’Informatique

7-
SELECT function, AVG(salaire)
FROM employe
GROUP BY fonction;
8-
SELECT SUM(salaire)
FROM employe
WHERE numdept = ( SELECT numdept
FROM departement
WHERE dnom=’Commercial’);
9-
SELECT enom
FROM employe
WHERE numdept IN ( SELECT numdept
FROM departement);
10-
SELECT enom,function,salaire
FROM employe
WHERE salaire >=ALL ( SELECT salaire
FROM employe);
11-
SELECT enom,function,salaire
FROM employe
WHERE salaire > ( SELECT salaire
FROM employe
WHERE enom=’Mohamed Tlili’);
12-
SELECT enom,salaire
FROM employe
WHERE salaire > ( SELECT AVG(salaire)
FROM employe
WHERE numdept= (SELECT numdept
FROM employe
WHERE dnom=’Commercial’
)
)
AND salaire < (SELECT MIN(salaire)
FROM employe
WHERE numdept= (SELECT numdept
FROM employe
WHERE dnom=’Comptabilite-finance’
)
);
13-
SELECT numdept, COUNT(*)
FROM employe
GROUP BY numdept;

14-
SELECT numdept, SUM(salaire)
FROM employe
GROUP BY numdept
HAVING COUNT(*)>3;

15-
SELECT enom
FROM employe
WHERE function=( SELECT function
FROM employe

68-Mohamed Fadhel SAAD SGBD


Département Technologies de l’Informatique
WHERE enom=’Mohamed Tlili’);

Atelier 2 
Exercice 1
Exécuter les scripts suivants, détecter les erreurs s’ils existent et les corrigent.

Exemple 2.1

Exemple 2.2

SGBD Mohamed Fadhel SAAD-69


Département Technologies de l’Informatique

Exemple 2.3

Exercice 2
1-
DECLARE
a NUMBER;
b NUMBER;
t NUMBER;
BEGIN
a:= 1;
b:= 2;
DBMS_OUTPUT.PUT_LINE('a = ' || a);
DBMS_OUTPUT.PUT_LINE(' b = ' || b);
DBMS_OUTPUT.PUT_LINE('Echanger a et b...Le resultat est:');
t:= a;
a:= b;
b:= t;
DBMS_OUTPUT.PUT_LINE('a = ' || a);
DBMS_OUTPUT.PUT_LINE('b = ' || b);
END;
2-
DECLARE
NO1 NUMBER; --LOCAL VARIABLE
NO2 NUMBER;
TOT NUMBER;
PER NUMBER;

70-Mohamed Fadhel SAAD SGBD


Département Technologies de l’Informatique
BEGIN
NO1:= &N1; --&N1 substitution variable
NO2:= &N2; --&N2 substitution variable
TOT:= NO1 + NO2;
PER:= TOT /2;
DBMS_OUTPUT.PUT_LINE(‘TOTAL ‘ || TOT);
DBMS_OUTPUT.PUT_LINE(‘MOYENNE ‘ || PER);
END;

Exercice 3
1-
DECLARE
t employe.salaire%TYPE;
BEGIN
SELECT salaire INTO t
FROM employe
WHERE empno=2000;

UPDATE employe
SET salaire= ( SELECT salaire
FROM employe
WHERE empno=2300)
WHERE empno=2000;
UPDATE employe
SET salaire= t
WHERE empno=2300;
END;
2-
DECLARE
vnom employe.enom%TYPE;
vfonction employe.fonction%TYPE;
vsalaire employe.salaire%TYPE;
BEGIN
SELECT enom, fonction, salaire
INTO vnom, vfonction, vsalaire
FROM employe
WHERE empno=1000;
DBMS_OUTPUT.PUT_LINE(‘Monsieur ‘ || vnom || ‘est recrute comme ‘||
vfonction || ‘ avec un salaire de ‘ || vsalaire);
END;

Exercice 4
1-
ACCEPT num PROMPT ‘Donner le numero de departement’

BEGIN
INSERT INTO departement
values(&num,NULL,NULL);
END;
b-
SELECT *
FROM departement
WHERE numdept=60;
c-
BEGIN
UPDATE departement
SET dnom = ‘Personnel’, localite = ‘Bizerte’ WHERE numdept=60;

SGBD Mohamed Fadhel SAAD-71


Département Technologies de l’Informatique

END;
d-
ACCEPT num PROMPT ‘Donner le numero de departement’
VARIABLE g_mess VARCHAR2(30)
DECLARE
v_resultat NUMBER(2);
BEGIN
DELETE FROM departement
WHERE numdept=&num;
v_resultat:= SQL%ROWCOUNT;
:g_mess:= TO_CHAR(v_resultat) || ‘ligne supprimee’;
END;

72-Mohamed Fadhel SAAD SGBD


Département Technologies de l’Informatique

Atelier 3 
Exercice 1
Exemple 3.1

Exemple 3.2

Exercice 2
SGBD Mohamed Fadhel SAAD-73
Département Technologies de l’Informatique

1-

DECLARE
v_mention CHAR(2);
v_note NUMBER(4,2):= 9.8;
BEGIN
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('La mention est ' || v_mention);
END;

2-

DECLARE
v_somme NUMBER(4):= 0;
v_entier NUMBER(3):= 1;
BEGIN
WHILE (v_entier<=100) LOOP
v_somme:= v_somme+v_entier;
v_entier:= v_entier + 1;
END LOOP;
DBMS_OUTPUT.PUT_LINE ('Somme = ' || v_somme);
END;

3-

DECLARE
v_somme NUMBER(4):= 0;
v_entier NUMBER(3):= 1;
BEGIN
LOOP
v_somme:= v_somme+v_entier;
v_entier:= v_entier + 1;
EXIT WHEN (v_entier >100);
END LOOP;
DBMS_OUTPUT.PUT_LINE ('Somme = ' || v_somme);
END;

4.

DECLARE
v_telephone CHAR(10):= '98 584 870';
v_trouve BOOLEAN:= FALSE;
v_indice NUMBER(2):= 1;
BEGIN
WHILE (v_indice<=10 AND NOT v_trouve) LOOP
IF SUBSTR(v_telephone,v_indice,1) = '9' THEN
v_trouve:= TRUE;
ELSE
v_indice:= v_indice + 1;
END IF;
END LOOP;
IF v_trouve THEN
DBMS_OUTPUT.PUT_LINE ('Trouve 9 à l''indice:' || v_indice);

74-Mohamed Fadhel SAAD SGBD


Département Technologies de l’Informatique
END IF;
END;

Exercice 3
Prompt "Quel employé cherchez-vous ?"
accept vnom

DECLARE
vfonction emplpye.fonction%type;
message CHAR(30);

BEGIN
SELECT fonction INTO vfonction
FROM employe
WHERE enom='&vnom';
-- contrôle de la valeur de vfonction --
IF vfonction IS NULL THEN
message:= '&vnom' || ' n''a pas de travail';
ELSE
IF vfonction='Vendeur' THEN
UPDATE empploye
SET commision=1000
WHERE enom='&vnom';
message:= '&vnom' || ' a 1000 Dinars de commission';
ELSE
UPDATE empploye
SET commision=0
WHERE enom='&vnom';
message:= '&vnom' || ' n''a pas de commission ';
END IF;
END IF;
DBMS_OUTPUT.PUT_LINE (message);
END;

Exercice 4
DECLARE
v_commission employe.commision%TYPE;
BEGIN
FOR i IN 1..50 LOOP
IF MOD(i,2) = 0 THEN
v_commission:= 500;
ELSE 
v_commission:= 300;
END IF;
UPDATE employe
SET commission = v_commission
WHERE numdept = i;
END LOOP;
END;

SGBD Mohamed Fadhel SAAD-75


Département Technologies de l’Informatique

Atelier 4 
Exercice 1
Exemple 4.1

Exercice 2
1-

DECLARE
CURSOR c_nom IS
(SELECT enom
FROM employe
WHERE salaire>500);

BEGIN
FOR nom IN c_nom LOOP
DBMS_OUTPUT.PUT_LINE('le nom='||nom.enom);
END LOOP;
END;

2-

ACCEPT sal PROMPT 'Donner la valeur du salaire'

DECLARE
CURSOR c_nom (sal NUMBER) IS
(SELECT enom

76-Mohamed Fadhel SAAD SGBD


Département Technologies de l’Informatique
FROM employe
WHERE salaire>sal);

BEGIN
FOR nom IN c_nom(&sal) LOOP
DBMS_OUTPUT.PUT_LINE('le nom='||nom.enom);
END LOOP;
END;

3-

DECLARE
CURSOR cur_emp IS
SELECT enom, fonction, salaire, numdept
FROM employe;

rs cur_emp %ROWTYPE;
BEGIN
OPEN cur_emp;
LOOP
FETCH cur_emp INTO rs;
EXIT WHEN cur_emp %NOTFOUND;
DBMS_OUTPUT.PUT_LINE(rs.enom || ‘ ‘ || rs.salaire || ‘ ‘
rs.fonction || ‘ ‘||rs.numdept);
END LOOP;
CLOSE cur_emp;
END;

4-

DECLARE
CURSOR cur_emp IS
SELECT empno, salaire
FROM employe;
rs cur_emp %ROWTYPE;
BEGIN
OPEN cur_emp;
LOOP
FETCH cur_emp INTO rs;
EXIT WHEN NOT cur_emp%FOUND;
IF rs.salaire <1200 THEN
UPDATE employe
SET salaire = salaire *1.08
WHERE empno=rs.empno;
ELSIF rs.salaire <2500 THEN
UPDATE employe
SET salaire = salaire *1.12
WHERE empno=rs.empno;
ELSIF rs.salaire <4500 THEN
UPDATE employe
SET salaire = salaire *1.15
WHERE empno=rs.empno;
ELSE
UPDATE employe
SET salaire = salaire *1.2
WHERE empno=rs.empno;
END IF;
END LOOP;
CLOSE cur_emp;
END;

SGBD Mohamed Fadhel SAAD-77


Département Technologies de l’Informatique

5-

DECLARE
CURSOR cur_emp
IS SELECT enom, salaire, salaire *1.2 ‘prime’
FROM employe;
BEGIN
FOR rs IN cur_emp P LOOP
DBMS_OUTPUT.PUT_LINE(rs.enom || ‘ ‘ || rs.salaire ||’ ‘
||rs.prime);
END LOOP;
END;

6-

DECLARE
CURSOR c1 is
SELECT empno, commission
FROM employe
WHERE commission IS NOT NULL;
FOR UPDATE OF commission;
comm c1%ROWTYPE;
BEGIN
OPEN c1;
FETCH c1 INTO comm;
WHILE c1%FOUND LOOP
UPDATE employe
SET commission = comm.commission * 2
WHERE CURRENT OF c1;
FETCH c1 INTO comm;
END LOOP;
CLOSE c1;
END;

Exercice 3
1-
CREATE TABLE tab1
( nom varchar2(40),
salaire NUMBER(10,3)
);
2-

ACCEPT n PROMPT ‘Nombre d”employes’


-- Debut du bloc PL/SQL
DECLARE
CURSOR cur_emp is
SELECT enom, salaire
FROM employe
WHERE salaire IS NOT NULL
ORDER BY salaire DESC;

enr_emp cur_emp %ROWTYPE;

78-Mohamed Fadhel SAAD SGBD


Département Technologies de l’Informatique
BEGIN
OPEN cur_emp;
FOR i IN 1..&n LOOP
FETCH cur_emp INTO enr_emp;
EXIT WHEN cur_emp%NOTFOUND;
INSERT INTO tab1
VALUES (enr_emp.enom, enr_emp.salaire);
END LOOP;
CLOSE cur_emp;
COMMIT;
END;
-- Fin du bloc PL/SQL
/
SELECT *
FROM tab1;

SGBD Mohamed Fadhel SAAD-79


Département Technologies de l’Informatique

Atelier 5 
Exercice 1
Exemple 5.1

Ce bloc permet de déterminer le nombre des tables utilisées.S’il est inferieur à 5, un message
d’erreur est apparu.

Exercice 2
DECLARE

nodept departement.numdept%TYPE;
nom departement.dnom%TYPE;
loc departement.localite%TYPE;

BEGIN
nodept:= & nodept;
SELECT dnom, localite
INTO nom, loc
FROM departement
WHERE numdept = nodept;
DBMS_OUTPUT.PUT_LINE(‘Nom de departement:’|| nom);
DBMS_OUTPUT.PUT_LINE(‘localite de departement:’|| loc);

EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE(‘Il n y a pas de département’);
END;

80-Mohamed Fadhel SAAD SGBD


Département Technologies de l’Informatique

Exercice 3
DECLARE
erreur_sal_min EXCEPTION;
erreur_sal_max EXCEPTION;
num employe.empno%TYPE:=1200;
nom employe.enom%TYPE:=’Ali’;
sal employe.salaire%TYPE:=’100’;

BEGIN
INSERT INTO employe(empno,enom,salaire)
VALUES(num, nom, sal);
IF sal<200 THEN
RAISE erreur_sal_min;
END IF;
IF sal>5000 THEN
RAISE erreur_sal_max;
END IF;

EXCEPTION
WHEN erreur_sal_min THEN
ROLLBACK;
DBMS_OUTPUT.PUT_LINE(‘Desole, salaire faible’);
WHEN erreur_sal_max THEN
ROLLBACK;
DBMS_OUTPUT.PUT_LINE(‘Desole, salaire trop grand’);
WHEN OTHERS THEN
ROLLBACK;
DBMS_OUTPUT.PUT_LINE(‘Erreur Oracle ’|| SQLERRM || ‘ (‘||
SQLCODE || ‘)’);
END;

Exercice 4
DECLARE
erreur_employe_inexistant EXCEPTION;
num employe.empno%TYPE:=1200;

BEGIN
DELETE FROM employe where empno=num;
IF SQL%NOTFOUND THEN
RAISE erreur_employe_inexistant;
END IF;
COMMIT;
DBMS_OUTPUT.PUT_LINE(‘Employe detruit ’);

EXCEPTION
WHEN erreur_employe_inexistant THEN
DBMS_OUTPUT.PUT_LINE(‘Employe Inexistant’);
WHEN OTHERS THEN
ROLLBACK;
DBMS_OUTPUT.PUT_LINE(‘Erreur Oracle ’|| SQLERRM || ‘ (‘||
SQLCODE || ‘)’);
END;

SGBD Mohamed Fadhel SAAD-81


Département Technologies de l’Informatique

Atelier 6 
Exercice 1

Exemple 6.1

C’est une fonction prend en paramètre une date et un séparateur et retourne la date dans le format
jour mois année, séparés par le séparateur fourni en paramètre.

Exemple 6.2

C’est une fonction prend en paramètre un entier et une chaine puis les concatène avec un – au
milieu.

82-Mohamed Fadhel SAAD SGBD


Département Technologies de l’Informatique

Exercice 2
1-
CREATE OR REPLACE PROCEDURE AugmenterSalaire
(wnum emp.empno%TYPE, wmont Real) IS
SalaireActuel emp.salaire%TYPE;
SalaireNull EXCEPTION;
BEGIN
SELECT salaire INTO SalaireActuel FROM employe
WHERE empno = wnum;
IF (SalaireActuel is NULL) THEN
RAISE SalaireNull;
ELSE
UPDATE emp
SET salaire = salaire + wmont
WHERE empno = wnum;
END IF;
EXCEPTION
WHEN NO_DATA_FOUND THEN
INSERT INTO emp_audit VALUES (wnum,'Inconnu');
WHEN SalaireNull THEN
INSERT INTO emp_audit VALUES (wnum,'Salaire Null');
END AugmenterSalaire;

2-
BEGIN
AugmenterSalaire(7435, 1000);
END;
3-
CREATE OR REPLACE FUNCTION MontantSalaire (NumDept IN employe.numdept
%TYPE)
RETURN REAL IS
wmont REAL;
BEGIN
SELECT SUM(salaire) INTO wmont
FROM employe
WHERE numdept = Numdept;
RETURN (wmont);
END MontantSalaire;

4-
CREATE OR REPLACE PROCEDURE award_bonus (emp_id NUMBER, bonus NUMBER) AS
vcommission REAL;
comm_missing EXCEPTION;
BEGIN
SELECT commission INTO vcommission
FROM employee
WHERE empno = emp_id;
IF vcommission IS NULL THEN
RAISE comm_missing;
ELSE
UPDATE employees
SET salaire = salaire + bonus*vcommission
WHERE empno = emp_id;
END IF;
EXCEPTION
WHEN comm_missing THEN
DBMS_OUTPUT.PUT_LINE (' Cet employé ne reçoit aucune
commission.');
WHEN OTHERS THEN NULL;

SGBD Mohamed Fadhel SAAD-83


Département Technologies de l’Informatique

END award_bonus;

Exercice 3
1-
CREATE OR REPLACE FUNCTION bad_puissance(b IN NUMBER, n IN NUMBER)
RETURN NUMBER IS
BEGIN
IF (n = 0) THEN
RETURN 1;
ELSE
RETURNbad_puissance(b , n -1);
END IF;
END;
2-

CREATE OR REPLACE FUNCTION good_puissance(b IN NUMBER, n IN NUMBER)


RETURN NUMBER IS
BEGIN
IF (n = 0) THEN
RETURN 1;
END IF;
IF (MOD (n ,2) = 0) THEN
RETURN good_puissance(b*b,n/2);
END IF;
RETURNb*good_puissance (b , n-1);
END;
3-
CREATE OR REPLACE PROCEDURE Conversion_d_euro
(prixD IN REAL,
prixE OUT REAL) IS
euro CONSTANT REAL:= 2.157;
prixnull EXCEPTION;
BEGIN
IF prixD IS NOT NULL THEN
prixE:= prixD/euro;
ELSE
RAISE prixnull;
END IF;
EXCEPTION
WHEN prixnull THEN
DBMS_OUTPUT.PUT_LINE('Calcul impossible');
END;

84-Mohamed Fadhel SAAD SGBD


Département Technologies de l’Informatique

Atelier 7 
Exercice 1

---------------------------------------------------
-- Contrainte 1 -----------------------------------
---------------------------------------------------

CREATE OR REPLACE TRIGGER beforeUpdateFERPrerequis


BEFORE UPDATE ON PREREQUIS
FOR EACH ROW
BEGIN
IF (:new.noteMin <:old.noteMin) THEN
:new.noteMin:=:old.noteMin;
END IF;
END;
/
---------------------------------------------------
-- Contrainte 2 -----------------------------------
---------------------------------------------------
CREATE OR REPLACE PROCEDURE incrEffec(module NUMBER) IS
BEGIN
UPDATE MODULE
SET effec = effec + 1
WHERE codmod = module;
END;
/
---------------------------------------------------
CREATE OR REPLACE PROCEDURE decrEffec (module NUMBER) IS
BEGIN
UPDATE MODULE
SET effec = effec - 1
WHERE codmod = module;
END;
/
---------------------------------------------------
CREATE OR REPLACE TRIGGER BeforeInsertFERModule
BEFORE INSERT ON MODULE
FOR EACH ROW
BEGIN
:new.effec:=0;
END;
/
---------------------------------------------------
CREATE OR REPLACE TRIGGER afterInsertFERInsc
AFTER INSERT ON INSCRIPTION
FOR EACH ROW
BEGIN
incrEffec(:new.codmod);
END;
/

SGBD Mohamed Fadhel SAAD-85


Département Technologies de l’Informatique

---------------------------------------------------
CREATE OR REPLACE TRIGGER afterDeleteFERInsc
AFTER DELETE ON INSCRIPTION
FOR EACH ROW
BEGIN
decrEffec(:old.codmod);
END;
/
---------------------------------------------------
CREATE OR REPLACE TRIGGER afterUpdateFERInsc
AFTER UPDATE ON INSCRIPTION
FOR EACH ROW
BEGIN
decrEffec(:old.codmod);
incrEffec(:new.codmod);END;
/

---------------------------------------------------
DROP VIEW modulesDisponibles;
CREATE VIEW modulesDisponibles AS
SELECT codmod
FROM MODULE
WHERE effec < effecMax;
---------------------------------------------------
CREATE OR REPLACE TRIGGER beforeInsertUpdateFERInsc
BEFORE INSERT OR UPDATE ON INSCRIPTION
FOR EACH ROW
DECLARE
nbLignes NUMBER;
BEGIN
SELECT count (*) INTO nbLignes
FROM modulesDisponibles
WHERE codmod =:new.codmod;
IF (nbLignes = 0) THEN
RAISE _ APPLICATION _ ERROR(-20001 , ' Plus de places
diponibles.');
END IF;
END;
/
---------------------------------------------------
-- Contrainte 3 -----------------------------------
---------------------------------------------------
DROP VIEW examensPossibles;
CREATE VIEW examensPossibles AS
SELECT codMod
FROM MODULE M
WHERE
( SELECT COUNT(*)
FROM INSCRIPTION I
WHERE I.codmod = M.codmod
) > 0;
---------------------------------------------------
CREATE OR REPLACE TRIGGER beforeInsertUpdateFERExam
BEFORE INSERT OR UPDATE ON EXAMEN
FOR EACH ROW
DECLARE
nbLignes NUMBER;
BEGIN
SELECT count (*) INTO nbLignes
FROM examensPossibles
WHERE codMod =:new.codmod;
IF (nbLignes = 0) THEN
RAISE _ APPLICATION _ ERROR(-20002,'Pas d"eleve dans ce module

86-Mohamed Fadhel SAAD SGBD


Département Technologies de l’Informatique
.');
END IF;
END;
/
---------------------------------------------------
-- Contrainte 4 -----------------------------------
---------------------------------------------------
DROP VIEW etudiantsExamens;
CREATE VIEW etudiantsExamens AS
SELECT I.numetud , E.codmod , E.codexam
FROM INSCRIPTION I , EXAMEN E
WHERE I.codmod = E.codmod
AND I.dateInsc < E.dateExam;
---------------------------------------------------
CREATE OR REPLACE TRIGGER beforeInsertUpdateFERResult
BEFORE INSERT OR UPDATE ON RESULTAT
FOR EACH ROW
DECLARE
nbLignes NUMBER;
BEGIN
SELECT count (*) INTO nbLignes
FROM etudiantsExamens
WHERE numetud =:new.numetud
AND codmod =:new.codmod
AND codexam =:new.codexam;
IF (nbLignes = 0) THEN
RAISE _ APPLICATION _ ERROR(-20002 , 'Examen anterieur a
l"inscription dans le module.');
END IF;
END;
/
---------------------------------------------------
-- Contrainte 5 -----------------------------------
---------------------------------------------------
-- On cree une table temporaire contenant les memes valeurs que
prerequis ,
-- On l a met a jour AVANT la table prerequis pour verifier que ----
-- l'insertion ne construit pas de circuit.
DROP TABLE MIRRORPREREQ;
CREATE TABLE MIRRORPREREQ
(codmod NUMBER,
codmodprereq NUMBER,
noteMin NUMBER);
---------------------------------------------------
CREATE OR REPLACE FUNCTION findModule (root number, moduleToFind number)
RETURN BOOLEAN IS
CURSOR C IS SELECT codmod FROM MIRRORPREREQ WHERE codmodprereq = root;
SON C%rowtype;
BEGIN
FOR SON IN C LOOP
IF (son.codmod = moduleToFind OR findModule(son.codmod,moduleToFind))
THEN
RETURN TRUE;
END IF;
END LOOP;
RETURN FALSE;
END;
/
---------------------------------------------------
CREATE OR REPLACE PROCEDURE insertMIRRORPREREQ(codmodValue NUMBER,
codmodprereqValue NUMBER, note NUMBER) IS
BEGIN
INSERT INTO MIRRORPREREQ (codmod , codmodprereq , noteMin)
VALUES(codmodValue , codmodprereqValue , note);

SGBD Mohamed Fadhel SAAD-87


Département Technologies de l’Informatique

END;
/
---------------------------------------------------
CREATE OR REPLACE PROCEDURE deleteMIRRORPREREQ (codmodValue NUMBER,
codmodprereq Value NUMBER) IS
BEGIN
DELETE FROM MIRRORPREREQ
WHERE codmod = codmodValue
AND codmodprereq = codmodprereq Value;
END;
/
---------------------------------------------------
CREATE OR REPLACE PROCEDURE updateMIRRORPREREQ (codmodValue NUMBER,
codmodNewValue NUMBER, codmodprereq Value NUMBER,
codmodprereqNewValue NUMBER,newNote NUMBER) IS
BEGIN
UPDATE MIRRORPREREQ
SET codmod = codmodNewValue ,
codmodprereq = codmodprereqNewValue ,
noteMin = newNote
WHERE codmod = codmodValue
AND codmodprereq = codmodprereqValue;
END;
/
---------------------------------------------------
CREATE OR REPLACE TRIGGER afterDeleteFERPrereq
AFTER DELETE ON PREREQUIS
FOR EACH ROW
BEGIN
delete MIRRORPREREQ (:old.codmod ,:old.codmodprereq);
END;
/
---------------------------------------------------
CREATE OR REPLACE TRIGGER beforeInsertUpdateFERPrereq
BEFORE INSERT OR UPDATE ON PREREQUIS
FOR EACH ROW
BEGIN
IF INSERTING THEN
insert MIRRORPREREQ (:new.codmod ,:new.codmodprereq
,:new.noteMin);
END IF;
IF UPDATING THEN
update MIRRORPREREQ (:old.codmod ,:new.codmod ,
:old.codmodprereq ,:new.codmodprereq ,:new.noteMin);
END IF;
IF (findModule (:new.codmod ,:new.codmod)) THEN
IF INSERTING THEN
delete MIRRORPREREQ (:new.codmod ,:new.codmodprereq);
END IF;
IF UPDATING THEN
update MIRRORPREREQ (:new.codmod ,:old.codmod ,
:new.codmodprereq ,:old.codmodprereq ,:old.noteMin);
END IF;
RAISE _ APPLICATION _ ERROR(-20003 ,'Circuit dans
prerequis.');
END IF;
END;
/
---------------------------------------------------
-- Contrainte 6 -----------------------------------
---------------------------------------------------
CREATE OR REPLACE FUNCTION checkINSCRIPTION (etud NUMBER, mod NUMBER)
RETURN BOOLEAN

88-Mohamed Fadhel SAAD SGBD


Département Technologies de l’Informatique
IS
CURSOR prereq IS
SELECT noteMin , codmodprereq
FROM MIRRORPREREQ
WHERE codmod = mod;
p prereq%rowtype;
nbLignes NUMBER;
BEGIN
FOR p IN prereq LOOP
SELECT count (*) INTO nbLignes
FROM RESULTAT
WHERE codmod = p.codmodprereq
AND numetud = etud
AND note < p.noteMin;
IF (nbLignes = 0) THEN
RETURN FALSE;
END IF;
END LOOP;
RETURN TRUE;
END;
/
---------------------------------------------------
CREATE OR REPLACE TRIGGER beforeInsertUpdateFERInsc
BEFORE INSERT OR UPDATE ON INSCRIPTION
FOR EACH ROW
DECLARE
nbLignes NUMBER;
BEGIN
SELECT count (*) INTO nbLignes
FROM modulesDisponibles
WHERE codmod =:new.codmod;
IF (nbLignes = 0) THEN
RAISE _ APPLICATION _ ERROR(-20001 ,'Plus de places
diponibles.');
END IF;
IF (NOT(checkINSCRIPTION (:new.numetud ,:new.codmod))) THEN
RAISE _ APPLIATION _ ERROR(-20004 ,' Prerequis non
satisfait.');
END IF;
END;
/
---------------------------------------------------
-- Contrainte 7 -----------------------------------
---------------------------------------------------
DROP TABLE MIRRORRESULT;
CREATE TABLE MIRRORRESULT
(numetud NUMBER,
codmod NUMBER,
codexam NUMBER,
note NUMBER,
PRIMARY KEY(numetud , codmod , codexam)
);
---------------------------------------------------
DROP VIEW MEILLEURENOTE;
CREATE VIEW MEILLEURENOTE AS
SELECT numetud , codmod , MAX(note) AS n o t e M a x
FROM MIRRORRESULT
GROUP BY numetud , codmod;
---------------------------------------------------
DROP VIEW N O M B R E INSCRIPTION s;
CREATE VIEW N O M B R E INSCRIPTION S AS
SELECT numetud ,
( SELECT COUNT(*)
FROM INSCRIPTION I

SGBD Mohamed Fadhel SAAD-89


Département Technologies de l’Informatique

WHERE I.numetud = E.numetud


) AS nbINSCRIPTION s
FROM ETUDIANTE;
---------------------------------------------------
DROP VIEW NOMBRENOTES;
CREATE VIEW NOMBRENOTES AS
SELECT numetud , ( SELECT COUNT(*) AS nbNotes
FROM MEILLEURENOTE M
WHERE M.numetud = E.numetud
) AS nbNotes
FROM ETUDIANTE;
---------------------------------------------------
CREATE OR REPLACE PROCEDURE update Moyenne (etud NUMBER)
IS
nbNotes NUMBER;
nbINSCRIPTIONs NUMBER;
BEGIN
SELECT nbNotes INTO nbNotes
FROM NOMBRENOTES
WHERE numetud = etud;
SELECT nbINSCRIPTIONs INTO nbINSCRIPTIONs
FROM NOMBEINSCRIPTIONS
WHERE numetud = etud;
IF (nbNotes = nbINSCRIPTIONs) THEN
UPDATE ETUDIANT
SET Moyenne =
(SELECT AVG(noteMax)
FROM MEILLEURENOTE
WHERE numetud = etud
)
WHERE numetud = etud;
ELSE
UPDATE ETUDIANT
SET Moyenne = NULL
WHERE numetud = etud;
END IF;
END;
/
---------------------------------------------------
CREATE OR REPLACE TRIGGER afterInsertFERResult
AFTER INSERT ON RESULTAT
FOR EACH ROW
BEGIN
INSERT INTO MIRRORRESULT
VALUES (:new.numetud ,:new.codmod ,:new.codexam ,:new.note);
updateMoyenne (:new.numetud);
END;
/
---------------------------------------------------
CREATE OR REPLACE TRIGGER afterUpdateFERResult
AFTER UPDATE ON RESULTAT
FOR EACH ROW
BEGIN
UPDATE MIRRORRESULT
SET numetud =:new.numetud ,
codmod =:new.codmod , codexam =:new.codexam , note =:new.note
WHERE numetud =:old.numetud
AND codmod =:old.codmod
AND codexam =:old.codexam;
updateMoyenne (:new.numetud);
END;
/

90-Mohamed Fadhel SAAD SGBD


Département Technologies de l’Informatique

---------------------------------------------------
CREATE OR REPLACE TRIGGER afterDeleteFERResult
AFTER DELETE ON RESULTAT
FOR EACH ROW
BEGIN
DELETE FROM MIRRORRESULT
WHERE numetud =:new.numetud
AND codmod =:new.codmod
AND codexam =:new.codexam;
updateMoyenne (:new.numetud);
END;
/
---------------------------------------------------
-- Contrainte 9 -----------------------------------
---------------------------------------------------
CREATE OR REPLACE FUNCTION checkAllStudents
RETURN BOOLEAN
IS
CURSOR C IS
SELECT numetud , codmod
FROM INSCRIPTION;
e C%rowtype;
BEGIN
FOR e IN C LOOP
IF (NOT(checkINSCRIPTION (e.numetud , e.codmod))) THEN
RETURN FALSE;
END IF;
END LOOP;
RETURN TRUE;
END;
/
---------------------------------------------------
CREATE OR REPLACE TRIGGER BeforeUpdateFERModule
BEFORE UPDATE ON MODULE
FOR EACH ROW
BEGIN
IF (:new.effecmax <:new.effec) THEN
RAISE _ APPLICATION _ ERROR(-20005 ,'L effectif ne peut etre
en dessous de ' ||:new.effec);
END IF;
END;
/
---------------------------------------------------
-- Contrainte 8 -----------------------------------
---------------------------------------------------
CREATE OR REPLACE TRIGGER beforeInsertUpdateFERPrereq
BEFORE INSERT OR UPDATE ON PREREQUIS
FOR EACH ROW
BEGIN
IF INSERTING THEN
insertMIRRORPREREQ (:new.codmod ,:new.codmodprereq
,:new.noteMin);
END IF;
IF UPDATING THEN
updateMIRRORPREREQ (:old.codmod ,:new.codmod ,
:old.codmodprereq ,:new.codmodprereq ,:new.noteMin);
END IF;
IF (findModule (:new.codmod ,:new.codmod)) THEN
IF INSERTING THEN
deleteMIRRORPREREQ (:new.codmod ,:new.codmodprereq);
END IF;
IF UPDATING THEN
updateMIRRORPREREQ (:new.codmod ,:old.codmod ,

SGBD Mohamed Fadhel SAAD-91


Département Technologies de l’Informatique

:new.codmodprereq ,:old.codmodprereq ,:old.noteMin);


END IF;
RAISE _ APPLICATION _ ERROR(-20003 , 'Circuit dans prerequis.');
END IF;
IF (NOT(checkAllStudents ())) THEN
IF INSERTING THEN
deleteMIRRORPREREQ (:new.codmod ,:new.codmodprereq);
END IF;
IF UPDATING THEN
updateMIRRORPREREQ (:new.codmod ,:old.codmod ,
:new.codmodprereq ,:old.codmodprereq ,:old.noteMin);
END IF;
RAISE _ APPLICATION _ ERROR(-20006 , ' Impossible de diminuer cette
note.');
END IF;
END;
/

92-Mohamed Fadhel SAAD SGBD