Aller au contenu

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 :

  1. Déclaration

    On déclare le curseur comme une variable dans la section DECLARE du bloc PL/SQL.

  2. Ouverture

    On alloue de la mémoire au curseur dans le bloc BEGIN.

  3. Traitement

    On effectue des opérations sur les lignes du curseur dans le bloc BEGIN.

  4. 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