Les curseurs¶
Un curseur est un mécanisme qui permet de :
- récupérer le résultat d’une requête SQL
- traiter chaque ligne séparément en PL/SQL
PROBLÈME
❌ Lorsque la requête retourne plusieurs lignes, on ne peut pas utiliser directement SELECT ... INTO.
🤔 Cette instruction s'utilise uniquement lorsqu'un retour de select du bon type peut être affecté à une variable.
SOLUTION
➡️ Le curseur permet de recevoir le résultat s'un SELECT de plusieurs lignes, puis de parcourir le résultat ligne par ligne.
Le curseur explicite¶
Les étpaes d'utilisation d'un curseur explicite sont :
-
Déclaration
On déclare le curseur comme une variable dans la section DECLARE du bloc PL/SQL.
-
Ouverture
On alloue de la mémoire au curseur dans le bloc BEGIN.
-
Traitement
On effectue des opérations sur les lignes du curseur dans le bloc BEGIN.
-
Fermeture
On libère la mémoire avant l'instruction END du bloc PL/SQL.
Exemple :
DECLARE
--Déclaration
CURSOR cur_peripherique IS
SELECT * FROM peripherique
WHERE prixPeripherique <20
ORDER BY prixPeripherique;
unPeripherique cur_peripherique%ROWTYPE;
nbrePeri NUMBER(2);
BEGIN
--Ouverture
OPEN cur_peripherique;
--Lit une ligne du curseur
FETCH cur_peripherique INTO unPeripherique;
--Boucle tant qu'une ligne a été trouvée dans le curseur
WHILE cur_peripherique%FOUND LOOP
dbms_output.put_line(unPeripherique.nomperi || ' est le périphérique ' || unPeripherique.noperi || ' et coûte ' || unPeripherique.prixperi);
FETCH cur_peripherique INTO unPeripherique;
END LOOP;
nbrePeri := cur_peripherique%ROWCOUNT;
dbms_output.put_line('Il existe ' || nbrePei || ' périphériques dont le prix est inférieur à 20$);
--Fermeture
CLOSE cur_peripherique;
END;
/
Opération FETCH¶
✏ Traite les données d’un curseur ligne par ligne.
--Lit la prochaine ligne du curseur
FETCH cur_peripherique INTO unPeripherique;
✏ Une variable de type “ ligne du curseur ” doit être déclarée.
unPeripherique cur_peripherique%ROWTYPE;
✏ Pour savoir si le FETCH a bien retourné une ligne, on utilise %FOUND ou %NOTFOUND
IF cur_peripherique%FOUND THEN
...
END IF;
Attributs utiles¶
Il existe des indicateurs d'état d'un curseur qui sont utiles pour connaître l'état du curseur et s'éviter des erreurs de traitement.
-
%FOUND
Retourne TRUE si le FETCH a retourné une nouvelle ligne
-
%NOTFOUND
Retourne TRUE si rle FETCH n'a retourné aucune ligne
-
%ISOPEN
Retourne TRUE si le curseur est ouvert
-
%ROWCOUNT
Retourne le numéro de la dernière ligne retournée par le FETCH (ATTENTION pas le nombre total de lignes !)
Curseur FOR¶
Puisque 90% du temps, on crée un curseur pour parcourir les lignes retournées par un SELECT, il existe une forme simplifiée du curseur qui effectue plusieurs tâches automatiquement pour nous :
- ✅ Le curseur est automatiquement ouvert lors de la boucle (pas de OPEN à écrire)
- ✅ La boucle récupère les lignes automatiquement (pas de FETCH à effectuer)
- ✅ La fin de la boucle END LOOP ferme le curseur automatiquement (Pas de CLOSE à inscrire)
- ✅ La boucle déclare la variable de ligne automatiquement (par de variable ROWTYPE à déclarer)
Ainsi, il ne reste qu'à déclarer le curseur, puis l'utiliser dans une boucle.
Exemple :
DECLARE
--Déclaration
CURSOR cur_peripherique IS
SELECT * FROM peripherique
WHERE prixPeripherique <20
ORDER BY prixPeripherique;
BEGIN
--La boucle ouvre, navigue et ferme le curseur
FOR unPeripherique IN cur_peripherique LOOP
dbms_output.put_line(unPeripherique.nomperi || ' est le périphérique ' || unPeripherique.noperi || ' et coûte '|| unPeripherique.prixperi);
END LOOP;
END;
/
Durée de vie du curseur
ATTENTION: Un curseur utilisé en curseur FOR n'existe que dans le boucle, pour le temps de la boucle.
Il n'existe ni avant, ni après la boucle.
Curseur explicite VS Curseur FOR¶
| Curseur Explicite | Curseur FOR |
|---|---|
| Doit être déclaré, ouvert, traité et fermé | Doit être déclaré et utilisé dans une boucle |
| Nécessite une variable de type %ROWTYPE | La variable est automatiquement déclarée dans le FOR |
| Utile lorsqu'on ne connaît pas le nombre de lignes retournées par un SELECT | Utile lorsqu'on sait que le retour du SELECT nécessite d'être parcouru ligne par ligne |
| Obligatoire si on a besoin des données du curseur en-dehors de la boucle | Utile uniquement pour une boucle de parcours |