Abdelouahed Sabri
abdelouahed.sabri@gmail.com 1
CHAPITRE 2:
LES CURSEURS
PL/SQL
CURSEURS
INTRODUCTION
 Chaque instruction SQL exécutée par le SGBD possède
un espace SQL privé qui contient des informations sur
l'instruction SQL et l'ensemble de données retournées:
 Est-ce que la requête SQL a affecté un enregistrement ou
non,
 Nombre de lignes qui sont affectées par une requête.
Comment connaitre ces informations en
PL/SQL après l’exécution d’une requête
SQL???
2
CURSEURS
INTRODUCTION
 En définit en PL/SQL un curseur comme un espace
mémoire qui contient le résultat d’une requête
SQL.
 PL/SQL utilise des curseurs pour tous les accès à
des informations de la base de données.
On peut dire que toutes les requêtes sont associées à
un curseur.
 On distingue deux types de curseurs SQL:
 Le curseur implicite: utilisé par le serveur Oracle
pour tester et analyser les requêtes SQL,
 les curseurs explicites : déclarés par les
programmeurs. 3
CURSEUR IMPLICITE
 Il est associé aux ordres SELECT, INSERT, DELETE
et UPDATE.
 Il est déclaré automatiquement pour chaque opération
du LMD (Langage de Manipulation de Données) de
SQL.
 NB: une requête SELECT ne doit retourner qu'un seul
enregistrement.
 Ce curseur, par défaut, porte le nom SQL (contrario
aux curseurs explicites où l’utilisateur spécifie un nom
pour le curseur) et il est exploitable après l’exécution
d’une instruction.
 L’exécution d’une nouvelle instruction remplace l’ancien
curseur par un nouveau 4
CURSEUR IMPLICITE
LES ATTRIBUTS D’UN CURSEUR
 Chaque curseur a des attributs.
 Ces attributs permettent de connaître un certain
nombre d’informations qui ont été renvoyées
après l’instruction du LMD SQL et qui peuvent
être utiles au programmeur.
Ils sont utilisés dans la section d’exécution ou
dans la section d’exceptions.
5
CURSEUR IMPLICITE
LES ATTRIBUTS D’UN CURSEUR
 Les principaux attributs sont les suivants:
6
Variable Attribut Description
%FOUND SQL%FOUND Booléen valant TRUE si la
dernière instruction LMD
affecte au moins un
enregistrement.
%NOTFOUND SQL%NOTFOUND Booléen valant TRUE si la
dernière instruction LMD
n’affecte aucun enregistrement.
%ROWCOUNT SQL%ROWCOUNT Nombre de lignes affectées par
la dernière instruction LMD.
CURSEUR IMPLICITE
 Après exécution, le code PL/SQL affiche le nombre
d’enregistrements mises-à-jour
7
DECLARE
v_salaire NUMBER := 3000;
v_count NUMBER;
BEGIN
UPDATE E_EMP SET SALAIRE = v_salaire WHERE NOM= ‘HASSAN’;
v_count :=SQL%ROWCOUNT;
dbms_output.put_line(v_count );
END;
/
 Exemple 1
CURSEUR IMPLICITE
 Exemple 2
8
VARIABLE g_count NUMBER
DECLARE
v_salaire NUMBER := 3050;
v_count NUMBER;
BEGIN
UPDATE E_EMP SET SALAIRE = v_salaire +500 WHERE NOM=
'HANIN' or NOM= 'HAMDI' ;
UPDATE E_EMP SET SALAIRE = v_salaire WHERE NOM=
'HASSAN';
:g_count := SQL%ROWCOUNT ;
commit;
END;
/
PRINT g_count
CURSEUR IMPLICITE
 Exercice:
Ecrire un programme qui permet de:
 Saisir en entrée le nom d'un employé,
 Vérifier que cet employé est présent dans la table
E_EMP. Si oui le supprimer.
9
CURSEUR IMPLICITE
 Solution
10
SET VERIFY OFF
ACCEPT nom_emp PROMPT 'nom employé : '
VARIABLE g_result VARCHAR2(50);
BEGIN
DELETE from E_EMP WHERE nom= '&nom_emp';
if SQL%FOUND THEN
:g_result:='l enregitsrement ' || '&nom_emp' || ' est
supprimé';
ELSE
:g_result:='Aucun enregistrement pour le nom: ' ||
'&nom_emp' || ' n existe';
END IF;
COMMIT;
END;
/
print g_result;
CURSEUR IMPLICITE
 Les curseurs implicites sont utilisés par le
serveur Oracle pour tester et analyser les
requêtes SQL,
 Les attributs: %FOUND, %NOTFOUND,
%ROWCOUNT
Comment faire pour traiter des requêtes
SELECT qui renvoies plusieurs
enregistrements??
11
CURSEURS EXPLICITES
 Pour traiter une requête SELECT qui retourne
plusieurs lignes, l'utilisateur doit définir un
curseur qui lui permet d'extraire la totalité des
lignes sélectionnées.
 On parle des curseurs explicites (ou programmables)
 Le traitement du SELECT se fera ligne par ligne.
12
CURSEURS EXPLICITES
 L'utilisation d'un curseur explicite (pour traiter
un ordre SELECT ramenant plusieurs lignes)
nécessite 4 étapes :
1. Déclaration du curseur,
2. Ouverture du curseur,
3. Traitement des lignes,
4. Fermeture du curseur.
13
CURSEURS EXPLICITES
DÉCLARATION
 La déclaration du curseur permet de stocker l'ordre (la
requête) SELECT dans le curseur.
 Un curseur est déclaré dans la partie DECLARE d’un
bloc PL/SQL.
 La syntaxe:
14
CURSOR nomcurseur IS la_requête_SELECT ;
 Exemple:
DECLARE
CURSOR c_product IS SELECT name, mark, QtyInStock FROM T_Product
WHERE ID=1;
…
CURSEURS EXPLICITES
OUVERTURE ET FERMETURE
 Une fois un curseur explicite est déclaré, et avant de
l’utiliser, il faut l’ouvrir.
 L’ouverture du curseur est en fait l’exécution de la
requête déclarée par celui-ci.
 L'étape d'ouverture permet d'effectuer les opérations
suivantes :
 l'allocation mémoire du curseur,
 l'analyse syntaxique de la requête,
 le positionnement de verrous éventuels (si select for
update...).
 Alors que la fermeture permet de libérer la place
mémoire allouée par l’ouverture. 15
CURSEURS EXPLICITES
OUVERTURE ET FERMETURE
 L’ouverture et la fermeture du curseur est effectuée
dans la partie exécution du bloc PL/SQL.
16
BEGIN
…
OPEN nomcurseur;
…
CLOSE nomcurseur;
…
END;
NB1 : Il faut bien faire attention à n’ouvrir que les curseurs qui sont
déjà déclarés,
NB2 : Il faut faire attention à ne fermer que les curseurs ouverts.
CURSEURS EXPLICITES
OUVERTURE ET FERMETURE
 Exemple
17
DECLARE
CURSOR c_product IS SELECT name, mark, QtyInStock FROM
T_Product WHERE ID=1;
BEGIN
OPEN c_product;
… /*Traitement des lignes*/
CLOSE c_product ;
END;
CURSEURS EXPLICITES
LE TRAITEMENT DES ENREGISTREMENTS
 Un des avantages des curseurs est de pouvoir traiter
(un par un) plusieurs enregistrements renvoyés par
une requêtes SQL.
 L’extraction de lignes est réalisée avec l'instruction
FETCH. … INTO.
 FETCH (Anglais): rapporter (français)
La syntaxe est la suivante :
18
FETCH nomcurseur INTO nomvariable1 [,nomvariableI] … | nomrecord;
CURSEURS EXPLICITES
LE TRAITEMENT DES ENREGISTREMENTS
 Exemple
19
DECLARE
CURSOR c_emp IS SELECT NO, NOM, SALAIRE FROM e_emp;
v_NO e_emp.no%TYPE;
v_NOM e_emp.NOM%TYPE;
v_SALAIRE e_emp.SALAIRE%TYPE;
BEGIN
OPEN c_emp;
FETCH c_emp INTO v_NO, v_NOM, v_SALAIRE;
dbms_output.put_line('NO: ' || v_NO || chr(9) || 'NOM: ' || v_NOM || chr(9) ||
' SALAIRE:' || v_SALAIRE);
CLOSE c_emp;
END;
 L'ordre FETCH ne ramène qu'une seule ligne à la fois.
 La ligne courante d’un curseur est déplacée à chaque appel de l’instruction
FETCH
 Si le curseur est en fin de tableau, la commande Fetch ne quitte pas
automatiquement le tableau, elle reste « bloqué e» sur le dernier
enregistrement.
CURSEURS EXPLICITES
LE TRAITEMENT DES ENREGISTREMENTS
 Exemple
20
DECLARE
CURSOR c_emp IS SELECT *FROM e_emp;
rty_employe e_emp%ROWTYPE;
BEGIN
OPEN c_emp;
FETCH c_emp INTO rty_employe;
dbms_output.put_line('NO: ' || rty_employe.NO || chr(9) || 'NOM: '
|| rty_employe.NOM || chr(9) || ' SALAIRE:' || rty_employe.SALAIRE);
FETCH c_emp INTO rty_employe;
dbms_output.put_line('NO: ' || rty_employe.NO || chr(9) || 'NOM: '
|| rty_employe.NOM || chr(9) || ' SALAIRE:' || rty_employe.SALAIRE);
CLOSE c_emp;
END;
CURSEURS EXPLICITES
LES ATTRIBUTS D’UN CURSEUR
 Les principaux attributs d’un curseur explicites
sont les suivants:
21
Variable Attribut Description
%FOUND Cur%FOUND Booléen valant TRUE si la dernière
instruction LMD affecte au moins un
enregistrement.
%NOTFOUND Cur%NOTFOUND Booléen valant TRUE si la dernière
instruction LMD n’affecte aucun
enregistrement.
%ROWCOUNT Cur%ROWCOUNT Nombre de lignes affectées par la dernière
instruction LMD.
%ISOPEN Cur% ISOPEN Cet attribut est de type booléen : la valeur
de l’attribut est TRUE si le curseur est
ouvert et FALSE si le curseur est fermé
CURSEURS EXPLICITES
LES ATTRIBUTS D’UN CURSEUR
 Exercice:
Ecrivez un programme PL/SQL qui permet
d’afficher tout les enregistrements (champs No,
Nom et Salaire) de la table E_EMP en utilisant la
structure répétitive WHILE-LOOP
22
CURSEURS EXPLICITES
LES ATTRIBUTS D’UN CURSEUR
23
DECLARE
CURSOR c_emp IS SELECT *FROM e_emp;
rty_employe e_emp%ROWTYPE;
BEGIN
OPEN c_emp;
FETCH c_emp INTO rty_employe;
WHILE (c_emp%FOUND) LOOP
dbms_output.put_line('NO: ' || rty_employe.NO || chr(9) ||
'NOM: ' || rty_employe.NOM || chr(9) || ' SALAIRE:' ||
rty_employe.SALAIRE);
FETCH c_emp INTO rty_employe;
END LOOP;
CLOSE c_emp;
END;
/
CURSEURS EXPLICITES
LA BOUCLE FOR
 L’utilisation de la boucle FOR dans les curseurs permet
de fournir au programmeur une structure simple et
efficace.
 Dans ce cas on parle de curseur semi-automatique.
 Si on utilise la boucle FOR dans les curseurs:
 On va Éviter les directives OPEN, FETCH et CLOSE,
 La boucle FOR s'arrête automatiquement après l’extraction
de la dernière ligne du curseur,
 la variable de réception du curseur est automatiquement
déclarée (%ROWTYPE du curseur).
24
CURSEURS EXPLICITES
LA BOUCLE FOR
25
DECLARE
CURSOR c_emp IS SELECT *FROM e_emp;
-- rty_employe c_emp%ROWTYPE;
BEGIN
-- OPEN c_emp;
-- FETCH c_emp INTO rty_employe;
FOR rty_employe IN c_emp LOOP
dbms_output.put_line('NO: ' || rty_employe.NO || chr(9) ||
'NOM: ' || rty_employe.NOM || chr(9) || ' SALAIRE:' ||
rty_employe.SALAIRE);
-- FETCH c_emp INTO rty_employe;
END LOOP;
-- CLOSE c_emp;
END;
CURSEURS EXPLICITES
LA BOUCLE FOR
26
DECLARE
CURSOR c_emp IS SELECT *FROM e_emp;
BEGIN
FOR rty_employe IN c_emp LOOP
dbms_output.put_line('NO: ' ||
rty_employe.NO || chr(9) || 'NOM: ' || rty_employe.NOM ||
chr(9) || ' SALAIRE:' || rty_employe.SALAIRE);
END LOOP;
END;
DECLARE
CURSOR c_emp IS SELECT *FROM e_emp;
rty_employe e_emp%ROWTYPE;
BEGIN
OPEN c_emp;
FETCH c_emp INTO rty_employe;
WHILE (c_emp%FOUND) LOOP
dbms_output.put_line('NO: ' ||
rty_employe.NO || chr(9) || 'NOM: ' || rty_employe.NOM ||
chr(9) || ' SALAIRE:' || rty_employe.SALAIRE);
FETCH c_emp INTO rty_employe;
END LOOP;
CLOSE c_emp;
END;
/
CURSEURS EXPLICITES
LA BOUCLE FOR
 On peut même éviter la déclaration du curseur
dans la partie DECLARE:
27
BEGIN
FOR rty_employe IN (SELECT *FROM e_emp) LOOP
dbms_output.put_line('NO: ' || rty_employe.NO || chr(9) || 'NOM: ' ||
rty_employe.NOM || chr(9) || ' SALAIRE:' || rty_employe.SALAIRE);
END LOOP;
END;
CURSEURS EXPLICITES
LA BOUCLE FOR
 Exercice:
Ecrivez un programme PL/SQL qui permet
d’afficher les enregistrements (champs No, Nom
et Salaire) de la table E_EMP qui ont un salaire
supérieur à la moyenne des salaires des employés
en utilisant la boucle FOR
28
CURSEURS EXPLICITES
LA BOUCLE FOR
 Solution
29
DECLARE
v_mean float;
BEGIN
select AVG(SALAIRE) into v_mean from E_EMP;
dbms_output.put_line('la moyenne des salaires est: ' || v_mean);
FOR rty_employe IN (SELECT *FROM e_emp where SALAIRE>=
v_mean) LOOP
dbms_output.put_line('NO: ' || rty_employe.NO || chr(9) ||
'NOM: ' || rty_employe.NOM || chr(9) || ' SALAIRE:' ||
rty_employe.SALAIRE);
END LOOP;
END;
CURSEURS EXPLICITES
LES CURSEURS PARAMÉTRABLES
 Un curseur peut avoir des paramètres en entrée.
 Ce passage de paramètre est très utile lorsqu’un
même curseur doit être utilisé plusieurs fois avec des
paramètres différents,
 À chaque appel paramétré il faut fermer le curseur,
s’il était déjà utilisé, pour l’ouvrir à nouveau en lui
passant d’autres paramètres (sauf si on utilise
l’instruction FOR ; car le curseur est fermé
automatiquement après chaque passage).
30
CURSEURS EXPLICITES
LES CURSEURS PARAMÉTRABLES
 Syntaxe:
31
 La requête SELECT utilise les paramètres passés par
le curseur,
 Les types de données (pour les paramètres du curseur)
possibles sont : CHAR, NUMBER, DATE, BOOLEAN
sans spécifier la longueur.
CURSOR nomcurseur (param1 type, param2 type,...) IS SELECT
la_requête_SELECT ;
CURSEURS EXPLICITES
LES CURSEURS PARAMÉTRABLES
 Exemple:
32
DECLARE
CURSOR c_emp (v_No e_emp.NO%TYPE) IS SELECT *FROM e_emp
WHERE NO=v_No;
rty_employe e_emp%ROWTYPE;
BEGIN
OPEN c_emp(1);
FETCH c_emp INTO rty_employe;
dbms_output.put_line('NO: ' || rty_employe.NO || chr(9) || 'NOM: '
|| rty_employe.NOM || chr(9) || ' SALAIRE:' || rty_employe.SALAIRE);
CLOSE c_emp;
OPEN c_emp(5);
FETCH c_emp INTO rty_employe;
dbms_output.put_line('NO: ' || rty_employe.NO || chr(9) || 'NOM: '
|| rty_employe.NOM || chr(9) || ' SALAIRE:' || rty_employe.SALAIRE);
CLOSE c_emp;
END;
CURSEURS EXPLICITES
ACCÈS CONCURRENTS (FOR UPDATE)
 Si on cherche à verrouiller les lignes d’une table
interrogée par un curseur pour les mettre à jour,
sans que d’autres utilisateurs ne les modifie en
même temps, il faut utiliser la clause FOR
UPDATE
 Elle est utilisée lors de la déclaration du curseur et
verrouille les lignes concernées lorsque le curseur est
ouvert,
 Les verrous sont libérés à la fin de la transaction.
33
CURSEURS EXPLICITES
ACCÈS CONCURRENTS (FOR UPDATE)
 Syntaxe:
34
CURSOR nomCurseur[(paramètres)] IS
SELECT … FROM {nomTable | nomVue } WHERE …
FOR UPDATE [OF [[schéma.] {nomTable | nomVue }.]colonne [, …]
[ NOWAIT | WAIT entier ]
 la directive OF permet de connaître les colonnes à verrouiller.
Sans elle, toutes les colonnes issues de la requête seront
verrouillées,
 NOWAIT précise de ne pas faire attendre le programme si les
lignes demandées sont verrouillées par une autre session,
 WAIT spécifie le nombre de secondes à attendre au maximum
avant que les lignes soient déverrouillées
 Sans NOWAIT et WAIT, le programme attend que les lignes soient
disponibles.
CURSEURS EXPLICITES
ACCÈS CONCURRENTS (FOR UPDATE)
 Pour modifier la ligne courante, il faut utiliser la
clause WHERE CURRENT OF nomCurseur
35
UPDATE nom_table SET VALUES … WHERE CURRENT OF nomCurseur;
CURSEURS EXPLICITES
ACCÈS CONCURRENTS (FOR UPDATE)
 Exemple
36
DECLARE
CURSOR c_emp IS SELECT *FROM e_emp FOR UPDATE OF SALAIRE NOWAIT;
BEGIN
FOR rty_emp IN c_emp LOOP
IF rty_emp.SERVICE_NO=1 THEN
update e_emp set SALAIRE =1000 WHERE CURRENT OF c_emp;
ELSIF rty_emp.SERVICE_NO=2 THEN
update e_emp set SALAIRE =2000 WHERE CURRENT OF c_emp;
ELSE
update e_emp set SALAIRE =3000 WHERE CURRENT OF c_emp;
END IF;
END LOOP;
COMMIT;
FOR rty_emp IN c_emp LOOP
dbms_output.put_line('NO: ' || rty_emp.NO || chr(9) || 'NOM: ' ||
rty_emp.NOM || chr(9) || 'SERVICE_NO: ' || rty_emp.SERVICE_NO|| chr(9) || ' SALAIRE:' ||
rty_emp.SALAIRE);
END LOOP;
END;
/
VARIABLES DE TYPES CURSEURS
 Une variable curseur (ou référence à un curseur REF
CURSOR) définit un curseur dynamique qui n’est pas
associé à aucune requête fixe (contrairement à un
curseur classique dit statique)
 Ainsi, une variable curseur permet au curseur d’évoluer au
cours du programme.
Une variable de type curseur est un type de type REF
CURSOR.
37
VARIABLES DE TYPES CURSEURS
 Une variable curseur est déclarée en deux étapes:
1. Déclaration du type,
2. Déclaration (instanciation) de la variable du type.
 Une variable REF CURSOR peut être définie dans un bloc
PL/SQL par les instructions suivantes:
38
TYPE nomTypeCurseurDynamique IS REF CURSOR [RETURN
typeRetourSQL];
nomCurseurDynamique nomTypeCurseurDynamique;
 Le type de retour, qui est facultatif, représente en général la
structure d’un enregistrement d’une table (ROWTYPE)
 Dans le cas ou un curseur inclut un type de retour, le curseur
dynamique est dit typé.
 Dans le cas inverse, il est non typé et permet une grande
flexibilité car toute requête peut y être associée.
VARIABLES DE TYPES CURSEURS
 Pour utiliser une variable curseur:
 On affecte une requête à cette variable de curseur dans le
corps du programme (bloc),
 Après, on peut utiliser cette variable de curseur comme
n'importe quel autre curseur.
 L’ouverture d’un curseur dynamique est commandée
par l’instruction OPEN FOR requête,
39
 La lecture du curseur s’opère toujours avec l’instruction
FETCH.
 La fermeture du curseur s’opère avec l’instruction CLOSE
 Pour changer la requête affectée au curseur il faut fermer le
curseur si il est ouvert
OPEN nomTypeCurseurDynamique FOR la_requéte;
VARIABLES DE TYPES CURSEURS
CURSEURS NON TYPÉS
40
DECLARE
TYPE ref_product IS REF CURSOR;
c_product ref_product;
var1 T_Product.name%TYPE ;
var2 T_Product.mark%TYPE ;
var3 T_Product.QtyInStock%TYPE ;
BEGIN
OPEN c_product FOR SELECT name, mark FROM T_Product WHERE ID=1;
FETCH c_product INTO var1, var2;
WHILE (c_product%FOUND) LOOP
DBMS_OUTPUT.PUT_LINE('ID=1, nom : ' || var1 || ' , marque: ' || var2 );
FETCH c_product INTO var1, var2;
END LOOP;
IF c_product%ISOPEN THEN
CLOSE c_product;
END IF;
OPEN c_product FOR SELECT QtyInStock FROM T_Product WHERE ID=1;
FETCH c_product INTO var3;
WHILE (c_product%FOUND) LOOP
DBMS_OUTPUT.PUT_LINE('ID=1, QtyInStock: ' || var3);
FETCH c_product INTO var3;
END LOOP;
CLOSE c_product;
END;
VARIABLES DE TYPES CURSEURS
CURSEURS TYPÉS
41
DECLARE
TYPE ref_product IS REF CURSOR RETURN T_Product%ROWTYPE;
c_product ref_product;
rty_product T_Product %ROWTYPE ;
BEGIN
OPEN c_product FOR SELECT * FROM T_Product WHERE NOT (ID=1);
FETCH c_product INTO rty_product;
WHILE (c_product%FOUND) LOOP
DBMS_OUTPUT.PUT_LINE('ID: ' || rty_product.ID|| ' , nom : ' ||
rty_product.name|| ' , marque: ' || rty_product.mark|| ' , QtyInStock: ' || rty_product.QtyInStock);
FETCH c_product INTO rty_product;
END LOOP;
IF c_product%ISOPEN THEN
CLOSE c_product;
END IF;
OPEN c_product FOR SELECT * FROM T_Product WHERE ID=1;
FETCH c_product INTO rty_product;
WHILE (c_product%FOUND) LOOP
DBMS_OUTPUT.PUT_LINE('ID: ' || rty_product.ID|| ' , nom : ' ||
rty_product.name|| ' , marque: ' || rty_product.mark|| ' , QtyInStock: ' || rty_product.QtyInStock);
FETCH c_product INTO rty_product;
END LOOP;
CLOSE c_product;
END;
VARIABLES DE TYPES CURSEURS
 Exercice:
Ecrivez deux programmes PL/SQL, en utilisant:
1. Les curseurs non typés
2. Les curseurs typés.
qui permettent d’augmenter de 5% les salaires des
employés qui ont un salaire inférieur à la moyenne des
salaires.
PS: Il faut faire attention à ce que le salaire inférieur des
employés soit celui d’un employé parmi ceux qui avait un salaire
inférieur à la moyenne.
Afficher le Nom, le salaire avant augmentation et le
salaire après augmentation de ces employés. 42

PL/SQL:les curseurs

  • 1.
  • 2.
    CURSEURS INTRODUCTION  Chaque instructionSQL exécutée par le SGBD possède un espace SQL privé qui contient des informations sur l'instruction SQL et l'ensemble de données retournées:  Est-ce que la requête SQL a affecté un enregistrement ou non,  Nombre de lignes qui sont affectées par une requête. Comment connaitre ces informations en PL/SQL après l’exécution d’une requête SQL??? 2
  • 3.
    CURSEURS INTRODUCTION  En définiten PL/SQL un curseur comme un espace mémoire qui contient le résultat d’une requête SQL.  PL/SQL utilise des curseurs pour tous les accès à des informations de la base de données. On peut dire que toutes les requêtes sont associées à un curseur.  On distingue deux types de curseurs SQL:  Le curseur implicite: utilisé par le serveur Oracle pour tester et analyser les requêtes SQL,  les curseurs explicites : déclarés par les programmeurs. 3
  • 4.
    CURSEUR IMPLICITE  Ilest associé aux ordres SELECT, INSERT, DELETE et UPDATE.  Il est déclaré automatiquement pour chaque opération du LMD (Langage de Manipulation de Données) de SQL.  NB: une requête SELECT ne doit retourner qu'un seul enregistrement.  Ce curseur, par défaut, porte le nom SQL (contrario aux curseurs explicites où l’utilisateur spécifie un nom pour le curseur) et il est exploitable après l’exécution d’une instruction.  L’exécution d’une nouvelle instruction remplace l’ancien curseur par un nouveau 4
  • 5.
    CURSEUR IMPLICITE LES ATTRIBUTSD’UN CURSEUR  Chaque curseur a des attributs.  Ces attributs permettent de connaître un certain nombre d’informations qui ont été renvoyées après l’instruction du LMD SQL et qui peuvent être utiles au programmeur. Ils sont utilisés dans la section d’exécution ou dans la section d’exceptions. 5
  • 6.
    CURSEUR IMPLICITE LES ATTRIBUTSD’UN CURSEUR  Les principaux attributs sont les suivants: 6 Variable Attribut Description %FOUND SQL%FOUND Booléen valant TRUE si la dernière instruction LMD affecte au moins un enregistrement. %NOTFOUND SQL%NOTFOUND Booléen valant TRUE si la dernière instruction LMD n’affecte aucun enregistrement. %ROWCOUNT SQL%ROWCOUNT Nombre de lignes affectées par la dernière instruction LMD.
  • 7.
    CURSEUR IMPLICITE  Aprèsexécution, le code PL/SQL affiche le nombre d’enregistrements mises-à-jour 7 DECLARE v_salaire NUMBER := 3000; v_count NUMBER; BEGIN UPDATE E_EMP SET SALAIRE = v_salaire WHERE NOM= ‘HASSAN’; v_count :=SQL%ROWCOUNT; dbms_output.put_line(v_count ); END; /  Exemple 1
  • 8.
    CURSEUR IMPLICITE  Exemple2 8 VARIABLE g_count NUMBER DECLARE v_salaire NUMBER := 3050; v_count NUMBER; BEGIN UPDATE E_EMP SET SALAIRE = v_salaire +500 WHERE NOM= 'HANIN' or NOM= 'HAMDI' ; UPDATE E_EMP SET SALAIRE = v_salaire WHERE NOM= 'HASSAN'; :g_count := SQL%ROWCOUNT ; commit; END; / PRINT g_count
  • 9.
    CURSEUR IMPLICITE  Exercice: Ecrireun programme qui permet de:  Saisir en entrée le nom d'un employé,  Vérifier que cet employé est présent dans la table E_EMP. Si oui le supprimer. 9
  • 10.
    CURSEUR IMPLICITE  Solution 10 SETVERIFY OFF ACCEPT nom_emp PROMPT 'nom employé : ' VARIABLE g_result VARCHAR2(50); BEGIN DELETE from E_EMP WHERE nom= '&nom_emp'; if SQL%FOUND THEN :g_result:='l enregitsrement ' || '&nom_emp' || ' est supprimé'; ELSE :g_result:='Aucun enregistrement pour le nom: ' || '&nom_emp' || ' n existe'; END IF; COMMIT; END; / print g_result;
  • 11.
    CURSEUR IMPLICITE  Lescurseurs implicites sont utilisés par le serveur Oracle pour tester et analyser les requêtes SQL,  Les attributs: %FOUND, %NOTFOUND, %ROWCOUNT Comment faire pour traiter des requêtes SELECT qui renvoies plusieurs enregistrements?? 11
  • 12.
    CURSEURS EXPLICITES  Pourtraiter une requête SELECT qui retourne plusieurs lignes, l'utilisateur doit définir un curseur qui lui permet d'extraire la totalité des lignes sélectionnées.  On parle des curseurs explicites (ou programmables)  Le traitement du SELECT se fera ligne par ligne. 12
  • 13.
    CURSEURS EXPLICITES  L'utilisationd'un curseur explicite (pour traiter un ordre SELECT ramenant plusieurs lignes) nécessite 4 étapes : 1. Déclaration du curseur, 2. Ouverture du curseur, 3. Traitement des lignes, 4. Fermeture du curseur. 13
  • 14.
    CURSEURS EXPLICITES DÉCLARATION  Ladéclaration du curseur permet de stocker l'ordre (la requête) SELECT dans le curseur.  Un curseur est déclaré dans la partie DECLARE d’un bloc PL/SQL.  La syntaxe: 14 CURSOR nomcurseur IS la_requête_SELECT ;  Exemple: DECLARE CURSOR c_product IS SELECT name, mark, QtyInStock FROM T_Product WHERE ID=1; …
  • 15.
    CURSEURS EXPLICITES OUVERTURE ETFERMETURE  Une fois un curseur explicite est déclaré, et avant de l’utiliser, il faut l’ouvrir.  L’ouverture du curseur est en fait l’exécution de la requête déclarée par celui-ci.  L'étape d'ouverture permet d'effectuer les opérations suivantes :  l'allocation mémoire du curseur,  l'analyse syntaxique de la requête,  le positionnement de verrous éventuels (si select for update...).  Alors que la fermeture permet de libérer la place mémoire allouée par l’ouverture. 15
  • 16.
    CURSEURS EXPLICITES OUVERTURE ETFERMETURE  L’ouverture et la fermeture du curseur est effectuée dans la partie exécution du bloc PL/SQL. 16 BEGIN … OPEN nomcurseur; … CLOSE nomcurseur; … END; NB1 : Il faut bien faire attention à n’ouvrir que les curseurs qui sont déjà déclarés, NB2 : Il faut faire attention à ne fermer que les curseurs ouverts.
  • 17.
    CURSEURS EXPLICITES OUVERTURE ETFERMETURE  Exemple 17 DECLARE CURSOR c_product IS SELECT name, mark, QtyInStock FROM T_Product WHERE ID=1; BEGIN OPEN c_product; … /*Traitement des lignes*/ CLOSE c_product ; END;
  • 18.
    CURSEURS EXPLICITES LE TRAITEMENTDES ENREGISTREMENTS  Un des avantages des curseurs est de pouvoir traiter (un par un) plusieurs enregistrements renvoyés par une requêtes SQL.  L’extraction de lignes est réalisée avec l'instruction FETCH. … INTO.  FETCH (Anglais): rapporter (français) La syntaxe est la suivante : 18 FETCH nomcurseur INTO nomvariable1 [,nomvariableI] … | nomrecord;
  • 19.
    CURSEURS EXPLICITES LE TRAITEMENTDES ENREGISTREMENTS  Exemple 19 DECLARE CURSOR c_emp IS SELECT NO, NOM, SALAIRE FROM e_emp; v_NO e_emp.no%TYPE; v_NOM e_emp.NOM%TYPE; v_SALAIRE e_emp.SALAIRE%TYPE; BEGIN OPEN c_emp; FETCH c_emp INTO v_NO, v_NOM, v_SALAIRE; dbms_output.put_line('NO: ' || v_NO || chr(9) || 'NOM: ' || v_NOM || chr(9) || ' SALAIRE:' || v_SALAIRE); CLOSE c_emp; END;  L'ordre FETCH ne ramène qu'une seule ligne à la fois.  La ligne courante d’un curseur est déplacée à chaque appel de l’instruction FETCH  Si le curseur est en fin de tableau, la commande Fetch ne quitte pas automatiquement le tableau, elle reste « bloqué e» sur le dernier enregistrement.
  • 20.
    CURSEURS EXPLICITES LE TRAITEMENTDES ENREGISTREMENTS  Exemple 20 DECLARE CURSOR c_emp IS SELECT *FROM e_emp; rty_employe e_emp%ROWTYPE; BEGIN OPEN c_emp; FETCH c_emp INTO rty_employe; dbms_output.put_line('NO: ' || rty_employe.NO || chr(9) || 'NOM: ' || rty_employe.NOM || chr(9) || ' SALAIRE:' || rty_employe.SALAIRE); FETCH c_emp INTO rty_employe; dbms_output.put_line('NO: ' || rty_employe.NO || chr(9) || 'NOM: ' || rty_employe.NOM || chr(9) || ' SALAIRE:' || rty_employe.SALAIRE); CLOSE c_emp; END;
  • 21.
    CURSEURS EXPLICITES LES ATTRIBUTSD’UN CURSEUR  Les principaux attributs d’un curseur explicites sont les suivants: 21 Variable Attribut Description %FOUND Cur%FOUND Booléen valant TRUE si la dernière instruction LMD affecte au moins un enregistrement. %NOTFOUND Cur%NOTFOUND Booléen valant TRUE si la dernière instruction LMD n’affecte aucun enregistrement. %ROWCOUNT Cur%ROWCOUNT Nombre de lignes affectées par la dernière instruction LMD. %ISOPEN Cur% ISOPEN Cet attribut est de type booléen : la valeur de l’attribut est TRUE si le curseur est ouvert et FALSE si le curseur est fermé
  • 22.
    CURSEURS EXPLICITES LES ATTRIBUTSD’UN CURSEUR  Exercice: Ecrivez un programme PL/SQL qui permet d’afficher tout les enregistrements (champs No, Nom et Salaire) de la table E_EMP en utilisant la structure répétitive WHILE-LOOP 22
  • 23.
    CURSEURS EXPLICITES LES ATTRIBUTSD’UN CURSEUR 23 DECLARE CURSOR c_emp IS SELECT *FROM e_emp; rty_employe e_emp%ROWTYPE; BEGIN OPEN c_emp; FETCH c_emp INTO rty_employe; WHILE (c_emp%FOUND) LOOP dbms_output.put_line('NO: ' || rty_employe.NO || chr(9) || 'NOM: ' || rty_employe.NOM || chr(9) || ' SALAIRE:' || rty_employe.SALAIRE); FETCH c_emp INTO rty_employe; END LOOP; CLOSE c_emp; END; /
  • 24.
    CURSEURS EXPLICITES LA BOUCLEFOR  L’utilisation de la boucle FOR dans les curseurs permet de fournir au programmeur une structure simple et efficace.  Dans ce cas on parle de curseur semi-automatique.  Si on utilise la boucle FOR dans les curseurs:  On va Éviter les directives OPEN, FETCH et CLOSE,  La boucle FOR s'arrête automatiquement après l’extraction de la dernière ligne du curseur,  la variable de réception du curseur est automatiquement déclarée (%ROWTYPE du curseur). 24
  • 25.
    CURSEURS EXPLICITES LA BOUCLEFOR 25 DECLARE CURSOR c_emp IS SELECT *FROM e_emp; -- rty_employe c_emp%ROWTYPE; BEGIN -- OPEN c_emp; -- FETCH c_emp INTO rty_employe; FOR rty_employe IN c_emp LOOP dbms_output.put_line('NO: ' || rty_employe.NO || chr(9) || 'NOM: ' || rty_employe.NOM || chr(9) || ' SALAIRE:' || rty_employe.SALAIRE); -- FETCH c_emp INTO rty_employe; END LOOP; -- CLOSE c_emp; END;
  • 26.
    CURSEURS EXPLICITES LA BOUCLEFOR 26 DECLARE CURSOR c_emp IS SELECT *FROM e_emp; BEGIN FOR rty_employe IN c_emp LOOP dbms_output.put_line('NO: ' || rty_employe.NO || chr(9) || 'NOM: ' || rty_employe.NOM || chr(9) || ' SALAIRE:' || rty_employe.SALAIRE); END LOOP; END; DECLARE CURSOR c_emp IS SELECT *FROM e_emp; rty_employe e_emp%ROWTYPE; BEGIN OPEN c_emp; FETCH c_emp INTO rty_employe; WHILE (c_emp%FOUND) LOOP dbms_output.put_line('NO: ' || rty_employe.NO || chr(9) || 'NOM: ' || rty_employe.NOM || chr(9) || ' SALAIRE:' || rty_employe.SALAIRE); FETCH c_emp INTO rty_employe; END LOOP; CLOSE c_emp; END; /
  • 27.
    CURSEURS EXPLICITES LA BOUCLEFOR  On peut même éviter la déclaration du curseur dans la partie DECLARE: 27 BEGIN FOR rty_employe IN (SELECT *FROM e_emp) LOOP dbms_output.put_line('NO: ' || rty_employe.NO || chr(9) || 'NOM: ' || rty_employe.NOM || chr(9) || ' SALAIRE:' || rty_employe.SALAIRE); END LOOP; END;
  • 28.
    CURSEURS EXPLICITES LA BOUCLEFOR  Exercice: Ecrivez un programme PL/SQL qui permet d’afficher les enregistrements (champs No, Nom et Salaire) de la table E_EMP qui ont un salaire supérieur à la moyenne des salaires des employés en utilisant la boucle FOR 28
  • 29.
    CURSEURS EXPLICITES LA BOUCLEFOR  Solution 29 DECLARE v_mean float; BEGIN select AVG(SALAIRE) into v_mean from E_EMP; dbms_output.put_line('la moyenne des salaires est: ' || v_mean); FOR rty_employe IN (SELECT *FROM e_emp where SALAIRE>= v_mean) LOOP dbms_output.put_line('NO: ' || rty_employe.NO || chr(9) || 'NOM: ' || rty_employe.NOM || chr(9) || ' SALAIRE:' || rty_employe.SALAIRE); END LOOP; END;
  • 30.
    CURSEURS EXPLICITES LES CURSEURSPARAMÉTRABLES  Un curseur peut avoir des paramètres en entrée.  Ce passage de paramètre est très utile lorsqu’un même curseur doit être utilisé plusieurs fois avec des paramètres différents,  À chaque appel paramétré il faut fermer le curseur, s’il était déjà utilisé, pour l’ouvrir à nouveau en lui passant d’autres paramètres (sauf si on utilise l’instruction FOR ; car le curseur est fermé automatiquement après chaque passage). 30
  • 31.
    CURSEURS EXPLICITES LES CURSEURSPARAMÉTRABLES  Syntaxe: 31  La requête SELECT utilise les paramètres passés par le curseur,  Les types de données (pour les paramètres du curseur) possibles sont : CHAR, NUMBER, DATE, BOOLEAN sans spécifier la longueur. CURSOR nomcurseur (param1 type, param2 type,...) IS SELECT la_requête_SELECT ;
  • 32.
    CURSEURS EXPLICITES LES CURSEURSPARAMÉTRABLES  Exemple: 32 DECLARE CURSOR c_emp (v_No e_emp.NO%TYPE) IS SELECT *FROM e_emp WHERE NO=v_No; rty_employe e_emp%ROWTYPE; BEGIN OPEN c_emp(1); FETCH c_emp INTO rty_employe; dbms_output.put_line('NO: ' || rty_employe.NO || chr(9) || 'NOM: ' || rty_employe.NOM || chr(9) || ' SALAIRE:' || rty_employe.SALAIRE); CLOSE c_emp; OPEN c_emp(5); FETCH c_emp INTO rty_employe; dbms_output.put_line('NO: ' || rty_employe.NO || chr(9) || 'NOM: ' || rty_employe.NOM || chr(9) || ' SALAIRE:' || rty_employe.SALAIRE); CLOSE c_emp; END;
  • 33.
    CURSEURS EXPLICITES ACCÈS CONCURRENTS(FOR UPDATE)  Si on cherche à verrouiller les lignes d’une table interrogée par un curseur pour les mettre à jour, sans que d’autres utilisateurs ne les modifie en même temps, il faut utiliser la clause FOR UPDATE  Elle est utilisée lors de la déclaration du curseur et verrouille les lignes concernées lorsque le curseur est ouvert,  Les verrous sont libérés à la fin de la transaction. 33
  • 34.
    CURSEURS EXPLICITES ACCÈS CONCURRENTS(FOR UPDATE)  Syntaxe: 34 CURSOR nomCurseur[(paramètres)] IS SELECT … FROM {nomTable | nomVue } WHERE … FOR UPDATE [OF [[schéma.] {nomTable | nomVue }.]colonne [, …] [ NOWAIT | WAIT entier ]  la directive OF permet de connaître les colonnes à verrouiller. Sans elle, toutes les colonnes issues de la requête seront verrouillées,  NOWAIT précise de ne pas faire attendre le programme si les lignes demandées sont verrouillées par une autre session,  WAIT spécifie le nombre de secondes à attendre au maximum avant que les lignes soient déverrouillées  Sans NOWAIT et WAIT, le programme attend que les lignes soient disponibles.
  • 35.
    CURSEURS EXPLICITES ACCÈS CONCURRENTS(FOR UPDATE)  Pour modifier la ligne courante, il faut utiliser la clause WHERE CURRENT OF nomCurseur 35 UPDATE nom_table SET VALUES … WHERE CURRENT OF nomCurseur;
  • 36.
    CURSEURS EXPLICITES ACCÈS CONCURRENTS(FOR UPDATE)  Exemple 36 DECLARE CURSOR c_emp IS SELECT *FROM e_emp FOR UPDATE OF SALAIRE NOWAIT; BEGIN FOR rty_emp IN c_emp LOOP IF rty_emp.SERVICE_NO=1 THEN update e_emp set SALAIRE =1000 WHERE CURRENT OF c_emp; ELSIF rty_emp.SERVICE_NO=2 THEN update e_emp set SALAIRE =2000 WHERE CURRENT OF c_emp; ELSE update e_emp set SALAIRE =3000 WHERE CURRENT OF c_emp; END IF; END LOOP; COMMIT; FOR rty_emp IN c_emp LOOP dbms_output.put_line('NO: ' || rty_emp.NO || chr(9) || 'NOM: ' || rty_emp.NOM || chr(9) || 'SERVICE_NO: ' || rty_emp.SERVICE_NO|| chr(9) || ' SALAIRE:' || rty_emp.SALAIRE); END LOOP; END; /
  • 37.
    VARIABLES DE TYPESCURSEURS  Une variable curseur (ou référence à un curseur REF CURSOR) définit un curseur dynamique qui n’est pas associé à aucune requête fixe (contrairement à un curseur classique dit statique)  Ainsi, une variable curseur permet au curseur d’évoluer au cours du programme. Une variable de type curseur est un type de type REF CURSOR. 37
  • 38.
    VARIABLES DE TYPESCURSEURS  Une variable curseur est déclarée en deux étapes: 1. Déclaration du type, 2. Déclaration (instanciation) de la variable du type.  Une variable REF CURSOR peut être définie dans un bloc PL/SQL par les instructions suivantes: 38 TYPE nomTypeCurseurDynamique IS REF CURSOR [RETURN typeRetourSQL]; nomCurseurDynamique nomTypeCurseurDynamique;  Le type de retour, qui est facultatif, représente en général la structure d’un enregistrement d’une table (ROWTYPE)  Dans le cas ou un curseur inclut un type de retour, le curseur dynamique est dit typé.  Dans le cas inverse, il est non typé et permet une grande flexibilité car toute requête peut y être associée.
  • 39.
    VARIABLES DE TYPESCURSEURS  Pour utiliser une variable curseur:  On affecte une requête à cette variable de curseur dans le corps du programme (bloc),  Après, on peut utiliser cette variable de curseur comme n'importe quel autre curseur.  L’ouverture d’un curseur dynamique est commandée par l’instruction OPEN FOR requête, 39  La lecture du curseur s’opère toujours avec l’instruction FETCH.  La fermeture du curseur s’opère avec l’instruction CLOSE  Pour changer la requête affectée au curseur il faut fermer le curseur si il est ouvert OPEN nomTypeCurseurDynamique FOR la_requéte;
  • 40.
    VARIABLES DE TYPESCURSEURS CURSEURS NON TYPÉS 40 DECLARE TYPE ref_product IS REF CURSOR; c_product ref_product; var1 T_Product.name%TYPE ; var2 T_Product.mark%TYPE ; var3 T_Product.QtyInStock%TYPE ; BEGIN OPEN c_product FOR SELECT name, mark FROM T_Product WHERE ID=1; FETCH c_product INTO var1, var2; WHILE (c_product%FOUND) LOOP DBMS_OUTPUT.PUT_LINE('ID=1, nom : ' || var1 || ' , marque: ' || var2 ); FETCH c_product INTO var1, var2; END LOOP; IF c_product%ISOPEN THEN CLOSE c_product; END IF; OPEN c_product FOR SELECT QtyInStock FROM T_Product WHERE ID=1; FETCH c_product INTO var3; WHILE (c_product%FOUND) LOOP DBMS_OUTPUT.PUT_LINE('ID=1, QtyInStock: ' || var3); FETCH c_product INTO var3; END LOOP; CLOSE c_product; END;
  • 41.
    VARIABLES DE TYPESCURSEURS CURSEURS TYPÉS 41 DECLARE TYPE ref_product IS REF CURSOR RETURN T_Product%ROWTYPE; c_product ref_product; rty_product T_Product %ROWTYPE ; BEGIN OPEN c_product FOR SELECT * FROM T_Product WHERE NOT (ID=1); FETCH c_product INTO rty_product; WHILE (c_product%FOUND) LOOP DBMS_OUTPUT.PUT_LINE('ID: ' || rty_product.ID|| ' , nom : ' || rty_product.name|| ' , marque: ' || rty_product.mark|| ' , QtyInStock: ' || rty_product.QtyInStock); FETCH c_product INTO rty_product; END LOOP; IF c_product%ISOPEN THEN CLOSE c_product; END IF; OPEN c_product FOR SELECT * FROM T_Product WHERE ID=1; FETCH c_product INTO rty_product; WHILE (c_product%FOUND) LOOP DBMS_OUTPUT.PUT_LINE('ID: ' || rty_product.ID|| ' , nom : ' || rty_product.name|| ' , marque: ' || rty_product.mark|| ' , QtyInStock: ' || rty_product.QtyInStock); FETCH c_product INTO rty_product; END LOOP; CLOSE c_product; END;
  • 42.
    VARIABLES DE TYPESCURSEURS  Exercice: Ecrivez deux programmes PL/SQL, en utilisant: 1. Les curseurs non typés 2. Les curseurs typés. qui permettent d’augmenter de 5% les salaires des employés qui ont un salaire inférieur à la moyenne des salaires. PS: Il faut faire attention à ce que le salaire inférieur des employés soit celui d’un employé parmi ceux qui avait un salaire inférieur à la moyenne. Afficher le Nom, le salaire avant augmentation et le salaire après augmentation de ces employés. 42