Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                

cor3+cours

Télécharger au format pdf ou txt
Télécharger au format pdf ou txt
Vous êtes sur la page 1sur 18

ESC Tunis / ISAMM 2e LBDAD

Chapitre 3 : Les curseurs

I. Référencement de types existants en PL/SQL

I.1) Notion de %TYPE


Référence un type existant qui est soit un type défini précédemment, soit une colonne d’une table.

I.1.A)Notation
nom_variable nom_variable_ref%TYPE ;
nom_variable nom_table.nom_colonne%TYPE ;

I.1.B)Exemples
Crédit REAL ;

Montant Crédit%TYPE ;

→ Montant et crédit ont le même type de données.


NumEtud Etudiant.NumE%TYPE ;

→ NumEtud a le même type de données que la colonne NumE de la table Etudiant.

I.2) Notion de %ROWTYPE


Référence une ligne d’une table

I.2.A)Notation
nom_variable nom_table%ROWTYPE ;

I.2.B)Exemple
UnClient Client%ROWTYPE ;

→ La variable UnClient a la même composition qu’une ligne de la table Client.

Ingénierie des bases de données 34


ESC Tunis / ISAMM 2e LBDAD

I.3) Le type RECORD


Le type enregistrement (Record) désigne l’ensemble des données logiquement liées et stockées dans des
champs.

I.3.A)Déclaration d’un type enregistrement


Exemple :
TYPE ETUDIANT IS RECORD

Numéro INTEGER,

Nom VARCHAR2 (20),

Age INTEGER

);

I.3.B)Déclaration d’une variable enregistrement


E1 ETUDIANT ;

II. Les curseurs


C’est une structure de données permettant de stocker le résultat d’une requête qui retourne plusieurs
tuples.
PL/SQL utilise des curseurs pour tous les accès à des informations de la base de données. Le langage
supporte à la fois l’emploi de curseurs implicites et explicites.
Les curseurs implicites sont ceux qui sont établis lorsqu’un curseur explicite n’a pas été déclaré. Il faut
utiliser des curseurs explicites ou des curseurs de boucles FOR dans toutes les requêtes qui renvoient
plusieurs lignes.

II.1) Déclaration d’un curseur


Les curseurs sont définis dans la zone des variables de sous-programmes PL/SQL en utilisant l’instruction
CURSOR NomCurseur IS suivie d’une requête SQL valide.

Ingénierie des bases de données 35


ESC Tunis / ISAMM 2e LBDAD

Exemple :
CURSOR calcul IS

SELECT numprod, prixuni

FROM produit ;

L’instruction SQL peut être n’importe quelle requête valide. Après son initialisation, les actions d’un
curseur peuvent être contrôlées avec les instructions OPEN, FETCH et CLOSE ou en utilisant une boucle
FOR.
NB :
Un tuple du curseur précédent sera de type calcul%ROWTYPE.

II.2) Opérations sur un curseur


II.2.A) Ouverture d’un curseur
OPEN NomCurseur ;

II.2.B) Gestion automatique d’un curseur


Exemple :
FOR tuple IN calcul LOOP

var1:=tuple.numprod ;

var2:=tuple.prixuni ;

END LOOP ;

II.2.C) Gestion manuelle d’un curseur


Exemple :
LOOP

FETCH calcul INTO tuple ;

...

Ingénierie des bases de données 36


ESC Tunis / ISAMM 2e LBDAD

EXIT WHEN calcul%NOTFOUND ;

END LOOP ;

II.2.D) Fermeture d’un curseur


CLOSE NomCurseur ;

II.3) Contrôle d’un curseur


Afin d’utiliser un curseur pour manipuler des données, il faut utiliser l’instruction OPEN pour exécuter la
requête et identifier toutes les lignes qui satisfont le critère de sélection. Les extractions ultérieures de
lignes sont réalisées avec l’instruction FETCH.
Notons que FETCH permet de se positionner sur la ligne suivante et de charger les données de
l’enregistrement courant dans une ou plusieurs variables.
Lorsque toutes les données sont traitées, l’instruction CLOSE clôt toute activité associée avec le curseur
ouvert.
Exemple :
Soit la table EMP(idemp, Nom, Age, Poste, Salaire, Anciennnete)
Le code suivant permet d’ouvrir le curseur CursEmp et de traiter les lignes extraites. Après l’extraction et
le traitement de toutes les informations, le curseur est fermé.
Version 1 :
DECLARE

CURSOR CursEmp IS

SELECT *

FROM Emp

Where poste = 'Directeur' ;

BEGIN

FOR cur IN CursEmp LOOP

DBMS_OUTPUT.PUT_LINE (cur.Nom || ' - ' || cur.Age);

Ingénierie des bases de données 37


ESC Tunis / ISAMM 2e LBDAD

END LOOP ;

CLOSE CursEmp ;

END ;

Version 2 :
DECLARE

CURSOR CursEmp IS

SELECT Nom, Age, Salaire

FROM Emp

Where poste = 'Directeur' ;

var1 Emp.Nom%TYPE;

var2 Emp.Age%TYPE;

BEGIN

OPEN CursEmp;

LOOP

FETCH CursEmp INTO var1, var2;

DBMS_OUTPUT.PUT_LINE (var1 || ' - ' || var2);

EXIT WHEN info%NOTFOUND;

END LOOP;

CLOSE CursEmp;

END;

Ingénierie des bases de données 38


ESC Tunis / ISAMM 2e LBDAD

II.4) Attributs des curseurs explicites


Il y a quatre attributs associés aux curseurs PL/SQL :
 %NOTFOUND
 %FOUND
 %ROWCOUNT
 %ISOPEN
Tous les attributs de curseur s’évaluent à TRUE, FALSE ou NULL, en fonction de la situation.

II.4.A) L’attribut %NOTFOUND


L’attribut %NOTFOUND s’évalue à FALSE quand une ligne est extraite, TRUE si le dernier FETCH n’a
pas renvoyé une valeur et NULL si le curseur SELECT n’a pas renvoyé de données.

II.4.B) L’attribut %FOUND


L’attribut %FOUND est l’opposé logique de %NOTFOUND par rapport à TRUE et FALSE, mais s’évalue
néanmoins à NULL si le curseur ne renvoie pas de données.

II.4.C) L’attribut %ROWCOUNT


%ROWCOUNT est utilisé pour connaître le nombre de lignes contenues dans un curseur.

II.4.D) L’attribut %ISOPEN


%ISOPEN, est évalué soit TRUE ou bien FALSE, suivant que le curseur associé est ouvert ou non. Avant
que le curseur ne soit ouvert et après qu’il soit fermé, %ISOPEN vaut FALSE. Dans les autres cas, cet
attribut s’évalue à TRUE.

II.5) Paramètres des curseurs


On peut spécifier des paramètres pour les curseurs de la même manière que pour des sous-programmes.

Ingénierie des bases de données 39


ESC Tunis / ISAMM 2e LBDAD

L’exemple suivant illustre la syntaxe de déclaration de curseurs avec des paramètres :


DECLARE

CURSOR C_Emp (rôle IN emp.Poste%TYPE) IS

SELECT *

FROM Emp

WHERE poste = 'Secrétaire' ;

BEGIN

FOR compteur IN C_Emp ('secrétaire')

LOOP

DBMS_OUTPUT.PUT_LINE (TO_CHAR (compteur.NumEmp) || '-' ||


compteur.NomEmp) ;

END LOOP ;

END ;

III. Applications

III.1) Activité 1
III.1.A) Énoncé
Déclarer un type nommé Personne basé sur deux types nommés respectivement IdPers et Adresse.

III.1.B) Correction
TYPE Personne IS RECORD

Ingénierie des bases de données 40


ESC Tunis / ISAMM 2e LBDAD

IdPers VARCHAR2 (40),

Adresse VARCHAR2 (60)

) ;

P1 Personne ; -- Variable de type Personne

III.2) Activité 2
III.2.A) Énoncé
Soit la base de données Aéroport composée de tables suivants :
 Avion (NumAv, NomAV, Capacité, Localisation)
 Pilote (NumPilote, NomPilote, Ville, Salaire)
 Vol (NumVol, #NumAv, #NumPilote, VilleDep, VilleArr, HeurDep, HeurArr)
On désire réduire de 12 % le temps de vol des avions 1 et 4. Pour les avions 2 et 8, la réduction du temps
de vol sera de 15 %.
On doit donc mettre à jour les nouveaux temps d’arrivée pour les avions concernés.
Écrire un bloc PL/SQL en utilisant un curseur permettant de lire les données suivantes : le numéro du vol,
le numéro de l’avion, l’heure de départ ainsi que celui d’arrivée pour les avions concernés par cette mise à
jour.
Pour chaque vol lu par le curseur, on va calculer le temps de vol et le réduire selon le pourcentage requis
afin de mettre à jour le champ HeurArr.

III.2.B) Correction
III.2.B.a) Version 1
DECLARE

CURSOR AvModif IS

SELECT NumVol, NumAv, HeurDep, HeurArr

FROM Vol

WHERE NumAv IN (1, 2, 4, 8) ;

Ingénierie des bases de données 41


ESC Tunis / ISAMM 2e LBDAD

VolModif AvModif%ROWTYPE ;

tvol REAL ;

BEGIN

FOR VolModif IN AvModif LOOP

tvol := VolModif.HeurArr – VolModif.HeurDep ;

IF (VolModif.NumAv IN (1,4)) THEN

tvol := tvol * 0.88 ;

ELSE

tvol := tvol * 0.85 ;

END IF ;

UPDATE Vol

SET HeurArr = VolModif.HeurDep + tvol ;

WHERE NumVol = VolModif.NumVol ;

END LOOP ;

END ;

III.2.B.b) Version 2
DECLARE

CURSOR AvModif IS

SELECT NumVol, NumAv, HeurDep, HeurArr

FROM Vol

Ingénierie des bases de données 42


ESC Tunis / ISAMM 2e LBDAD

WHERE NumAv IN (1, 2, 4, 8) ;

VolModif AvModif%ROWTYPE ;

tvol REAL ;

Ha AvModif.HeurArr%type ;

Hd AvModif.HeurDep%type ;

nv AvModif.NumVol%type ;

Na AvModif.NumAv%type ;

BEGIN

OPEN AvModif;

LOOP

FETCH AvModif INTO nv, na, hd, ha;

tvol = ha – hd ;

IF (na IN (1,4)) THEN

tvol := tvol * 0.88 ;

ELSE

tvol := tvol * 0.85 ;

END IF ;

UPDATE Vol

SET HeurArr = hd + tvol ;

WHERE NumVol = nv ;

EXIT WHEN AvModif%NOTFOUND;

Ingénierie des bases de données 43


ESC Tunis / ISAMM 2e LBDAD

END LOOP ;

close AvModif ;

END ;

III.3) Activité 3
III.3.A) Énoncé
On souhaite supprimer les valeurs en double (doublons) d’une colonne nommée « db1 » présente dans la
table Test.
1) Écrire un bloc PL/SQL permettant d’afficher les valeurs présentes au moins en double puis les
supprimer
2) Peut-on ajouter une contrainte de clé primaire sur cette colonne à partir du bloc PL/SQL ?

III.3.B) Correction
1)
DECLARE

CURSOR Doublons IS

SELECT db1

FROM Test

GROUP BY db1

HAVING CONUT (*) > 1 ;

n Doublons%ROWTYPE ;

BEGIN

DBMS_OUTPUT.PUT_LINE (''Affichage des doublons'') ;

Ingénierie des bases de données 44


ESC Tunis / ISAMM 2e LBDAD

FOR n IN Doublons LOOP

DBMS_OUTPUT.PUT_LINE (n.db1) ;

DELETE FROM Test

WHERE n.db1 = Test.db1 ;

INSERT INTO Test

VALUES (n.db1) ;

END LOOP ;

2)
ALTER TABLE Test

ADD CONSTRAINT PK PRIMARY KEY (db1) ;

END ;

III.4) Activité 4
III.4.A) Énoncé
Soit la base de données suivante :
 DEP (NumDep, NomDep, Emplacement)
 Emp (NumEmp, NomEmp, Poste, Salaire, Commission, DateRecrut, #NumDep)
1) Écrire un bloc PL/SQL pour attribuer à l’employé numéro 140 une commission comme suit :
 Si l’employé occupe le poste de vendeur, sa commission est de 100 dinars ;
 Si l’employé occupe un autre poste alors il n’aura pas de commissions ;

Ingénierie des bases de données 45


ESC Tunis / ISAMM 2e LBDAD

 Si l’employé n’existe pas alors on affichera un message d’erreur.


2) Écrire un bloc PL/SQL pour afficher les n salaires les plus élevées de la table Emp.
3) Écrire un bloc PL/SQL pour retourner au plus 15 employés du département 8 ayant un salaire
supérieur à 1000 dinars.
4) Utiliser deux curseurs dont au moins un est paramétré pour trouver les n salaires les plus élevées
en tenant compte des doublons
5) Reprendre la question 2 de cet exercice pour traiter l'erreur Oracle NO_DATA_FOUND
(Renommer l’erreur et afficher un message approprié. Rappelons que le code de cette erreur est
+100)
III.4.B) Correction
1)
DECLARE

Num Emp.NumEmp%TYPE ;

BEGIN

SELECT NumEmp INTO Num

FROM Emp

WHERE NumEmp = 140 ;

IF Num ISNULL THEN

DBMS_OUTPUT.PUT_LINE (''L'employé n'existe pas!'') ;

ELSEIF Num = 140 THEN

UPDATE Emp

SET Commission = 100

WHERE NumEmp = Num AND Poste = ‘Vendeur’ ;

ELSE

UPDATE Emp

Ingénierie des bases de données 46


ESC Tunis / ISAMM 2e LBDAD

SET Commission = 0

WHERE NumEmp = Num AND Poste <> ‘Vendeur’ ;

END IF ;

COMMIT ;

END ;

2)
ACCEPT n PROMPT ''Donner n'' ;

DECLARE

CURSOR C1 IS

SELECT NomEmp, Salaire

FROM Emp

ORDER BY Salaire DESC ;

Nom Emp.NomEmp%TYPE ;

Sal Emp.Salaire%TYPE ;

i Number ;

BEGIN

OPEN C1

FOR i IN 1.. &n LOOP // & connaître n

FETCH C1 INTO Nom, Sal ;

Ingénierie des bases de données 47


ESC Tunis / ISAMM 2e LBDAD

INSERT INTO Res

VALUES (Nom, Sal) ;

END LOOP ;

CLOSE C1 ;

END ;

SELECT *

FROM Res ;

3)
DECLARE

CURSOR CS IS

SELECT NomEmp, Salaire

FROM Emp

WHERE (NumDep = 8) AND (Salaire > 1000) ;

Nom Emp.NomEmp%TYPE ;

Sal Emp.Salaire%TYPE ;

BEGIN

OPEN CS

LOOP

Ingénierie des bases de données 48


ESC Tunis / ISAMM 2e LBDAD

FETCH CS INTO Nom, Sal ;

EXIT WHEN CS%NOTFOUND OR CS%ROWCONUT > 15 ;

INSERT INTO Tmp

VALUES (Nom, Sal) ;

END LOOP ;

END ;

SELECT *

FROM Tmp ;

4)
ACCEPT n PROMPT ''Donner n'' ;

DECLARE

CURSOR C IS

SELECT DISTINCT Salaire

FROM Emp

ORDER BY Salaire DESC ;

CURSOR D (V NUMBER) IS -- ou bien Emp.Salaire%TYPE

SELECT NumEmp, NomEmp

FROM Emp

Ingénierie des bases de données 49


ESC Tunis / ISAMM 2e LBDAD

WHERE Salaire = V ;

Sal Emp.Salaire%TYPE ;

i NUMBER ;

BEGIN

OPEN C ;

LOOP

FETCH C INTO Sal ;

EXIT WHEN C%NOTFOUND OR C%ROWCOUNT > &n ;

FOR i IN D (V) LOOP

INSERT INTO Tmp

VALUES (i.NumEmp, i.NomEmp) ;

END LOOP ;

END LOOP ;

CLOSE C ;

END ;

SELECT *

FROM Tmp ;

Ingénierie des bases de données 50


ESC Tunis / ISAMM 2e LBDAD

5)
DECLARE

CURSOR C1 IS

......

CurVide EXCEPTION;

PRAGMA_EXCEPTION_INIT (CurVide, +100);

BEGIN

....

EXCEPTION

WHEN CurVide THEN

RAISE_APPLICATION_ERROR (-20010, ''message d'erreur'');

END;

Ingénierie des bases de données 51

Vous aimerez peut-être aussi