Si vous utilisez beaucoup les procédures stockées MySQL, vous avez sans doute eu le besoin de boucler sur un jeu d’enregistrement pour traiter un jeu de données. Cela peut se faire au travers d’un curseur (Cursor) MySQL.

Déclaration d’un curseur

Pour déclarer un curseur, il faut utiliser l’instruction DECLARE CURSOR avec le SELECT permettant d’avoir le jeu de données dans la zone de déclaration de la procédure (donc après le BEGIN et avant les HANDLERS).
Prenons l’exemple d’un curseur qui boucler sur tous les prix d’une base article :

 DECLARE monCurseur CURSOR FOR SELECT prix_ht, taux_tva, prix_ttc FROM article_tarif; 

Boucler sur les résultats du curseur

Pour boucler sur les résultats d’un curseur, il va falloir ouvrir le curseur et la boucle, affecter les champs de la ligne à des variables, faire les traitements que vous souhaitez, et enfin fermer la boucle et le curseur :


DECLARE var_prix_ht DECIMAL(18,2);
DECLARE var_taux_tva DECIMAL(18,2);
DECLARE var_prix_ttc DECIMAL(18,2);
...

OPEN monCurseur;
tarif_loop: LOOP
  FETCH monCurseur INTO var_prix_ht, var_taux_tva, var_prix_ttc;
  ...
END LOOP;
CLOSE monCurseur;

Une fois vos variables alimentées par le FETCH, vous pouvez faire les différents traitements appropriés. Si jamais vous avez des valeurs nulles dans vos variables après un FETCH et que vous ne comprenez pas pourquoi, vous pouvez jeter un oeil à cet article du site.

Définir une condition d’arrêt à la boucle

En l’état, avec le code ci-dessus vous aurez une erreur d’exécution lorsqu’il va parcourir le curseur et arriver à la fin du jeu d’enregistrement. Pour éviter cela, et pour avoir également une condition de sortie à la boucle (et éviter une éventuelle boucle infinie), vous allez pouvoir définir un HANDLER dédié.


DECLARE done INT DEFAULT 0;
...
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;
...
/* dans la boucle */
IF done = 1 THEN
LEAVE tarif_loop;
END IF;

Autre façon de sortir également, vous pouvez mettre à NULL vos variables en fin de tour, et tester si une variable qui ne devrait pas être nulle l’est dans la boucle, et faire le LEAVE à ce moment là


/* dans la boucle */
IF var_prix_ht IS NULL THEN
LEAVE tarif_loop;
END IF;
...
SET var_prix_ht = NULL;

En résumé, le code complet de notre exemple serait le suivant :


DECLARE var_prix_ht DECIMAL(18,2);
DECLARE var_taux_tva DECIMAL(18,2);
DECLARE var_prix_ttc DECIMAL(18,2);
DECLARE done INT DEFAULT 0;
DECLARE monCurseur CURSOR FOR
SELECT prix_ht, taux_tva, prix_ttc FROM article_tarif;

DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;

OPEN monCurseur;
tarif_loop: LOOP
FETCH monCurseur INTO var_prix_ht, var_taux_tva, var_prix_ttc;

IF done = 1 THEN
LEAVE tarif_loop;
END IF;

/* mettre ici le traitement à effectuer */

END LOOP;
CLOSE monCurseur;

Ressources

Documentation officielle