web-dev-qa-db-fra.com

Plusieurs curseurs dans des boucles imbriquées dans MySQL

Je souhaite faire quelque chose qui semble un peu compliqué dans MySQL. En fait, je souhaite ouvrir un curseur, faire une boucle, et dans cette boucle, ouvrir un deuxième curseur en utilisant les données de l'extraction précédente pour être exécuté, et re-boucle sur les résultats.

  DECLARE idind INT;
  DECLARE idcrit INT;
  DECLARE idindid INT;
  DECLARE done INT DEFAULT 0;
  DECLARE done2 INT DEFAULT 0;
  DECLARE curIndicateur CURSOR FOR SELECT id_indicateur FROM indicateur;
  DECLARE curCritereIndicateur CURSOR FOR SELECT C.id_critere FROM critere C where C.id_indicateur=idind;
  DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET done = 1;

  set idindid=54;
  OPEN curIndicateur;
  REPEAT
    FETCH curIndicateur INTO idind;
    open curCritereIndicateur;
    REPEAT
      FETCH curIndicateur INTO idcrit;
      INSERT INTO SLA_DEMANDE_STATUS (iddemande,idindicateur,indicateur_status,progression) values('0009',idcrit,'OK',10.0);
    UNTIL done END REPEAT;
    close curCritereIndicateur;
  UNTIL done END REPEAT;
  CLOSE curIndicateur;

En fait, comment faire "Until done" différemment pour les deux curseurs, car vous ne pouvez déclarer qu'un seul gestionnaire pour SQLSTATE? Si le premier se termine, le second se termine également.

14
user5537

Vous devez définir un nouveau BLOC dans votre première boucle de curseur et utiliser différentes déclarations dans ce bloc.

Quelque chose comme:

BLOCK1: begin
    declare v_col1 int;                     
    declare no_more_rows boolean1 := FALSE;  
    declare cursor1 cursor for              
        select col1
        from   MyTable;
    declare continue handler for not found  
        set no_more_rows1 := TRUE;           
    open cursor1;
    LOOP1: loop
        fetch cursor1
        into  v_col1;
        if no_more_rows1 then
            close cursor1;
            leave LOOP1;
        end if;
        BLOCK2: begin
            declare v_col2 int;
            declare no_more_rows2 boolean := FALSE;
            declare cursor2 cursor for
                select col2
                from   MyOtherTable
                where  ref_id = v_col1;
           declare continue handler for not found
               set no_more_rows2 := TRUE;
            open cursor2;
            LOOP2: loop
                fetch cursor2
                into  v_col2;
                if no_more_rows then
                    close cursor2;
                    leave LOOP2;
                end if;
            end loop LOOP2;
        end BLOCK2;
    end loop LOOP1;
end BLOCK1;
23
Pentium10

Ou redéfinissez le CONTINUER POIGNEE:

//...
LOOP1: LOOP
      fetch cursor1
      into  v_col1;
      if no_more_rows1 then
         close cursor1;
         leave LOOP1;
      end if;
//...

      SET no_more_rows1=false;//That's new
END LOOP LOOP1;          

Il semble que toutes les instructions select dans une boucle exécutent la commande CONTINUE HANDLE.

0
B.F.
DECLARE _idp INT;
DECLARE _cant INT;
DECLARE _rec INT;
DECLARE done INT DEFAULT 0;
-- Definición de la consulta
DECLARE primera CURSOR FOR SELECT dp.id_prod, SUM(dp.cantidad) AS cantidad, pp.receta FROM tm_detalle_pedido AS dp INNER JOIN tm_producto_pres AS pp
DECLARE segunda CURSOR FOR SELECT id_ins, cant FROM tm_producto_ingr WHERE id_pres = _idp;

-- Declaración de un manejador de error tipo NOT FOUND
DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;

-- Abrimos el primer cursor
OPEN primera;

REPEAT

FETCH primera INTO _idp, _cant, _rec;

IF NOT done THEN

 OPEN segunda;
 block2: BEGIN
     DECLARE doneLangLat INT DEFAULT 0;
     DECLARE _ii INT;
     DECLARE i FLOAT;
     DECLARE _canti FLOAT;
     DECLARE CONTINUE HANDLER FOR NOT FOUND SET doneLangLat = 1;

     REPEAT
     FETCH segunda INTO _ii,_canti;
     IF NOT doneLangLat THEN
        IF _rec = 1 THEN
            SET i = _canti * _cant;
            -- Insertamos
            INSERT INTO tm_inventario (id_ins,id_tipo_ope,id_cv,cant,fecha_r) 
            VALUES (_ii, 2, @id, i, _fecha);
        END IF;
     END IF;
     UNTIL doneLangLat END REPEAT;

  END block2;
  CLOSE segunda;

 END IF;

 UNTIL done END REPEAT;
 CLOSE primera;
0
Tommy Leonard

vous pouvez utiliser loop et redéfinir la valeur du handle, comme ceci:

get_something:loop
  open cur;
  fetch cur into temp_key;
  if no_more_record=1 then
    set no_more_record=0;
    close cur;
    leave get_something;
  else
    //do your job;
  end if;
end loop;
0
hyphen

Corrigez-moi si je me trompe, mais il semblerait que vous essayiez de créer une insertion en bloc d'enregistrements dans votre table "SLA_DEMANDE_STATUS". Incluez tous les critères pour chaque indicateur trouvé et attribuez-lui par défaut les valeurs «0009», «OK» et 10,0 pour chaque identifiant de critère. 

Tout cela peut être fait en une seule insertion SQL. INSERT INTO ... à partir d'un SQL-Select ...

Maintenant, si vous souhaitez inclure uniquement une seule entrée "id_indicateur", vous pouvez l'ajouter à la clause WHERE de l'instruction select.

Notez que mon SQL-Select a forcé les valeurs à correspondre aux colonnes que vous voulez avoir renseignées. Ils seront tous insérés dans la table de destination du même nom. La bonne chose à ce sujet, vous pouvez simplement exécuter la partie SQL-SELECT uniquement pour voir les données que vous vous attendriez à avoir insérées ... si elles sont incorrectes, vous pouvez les ajuster pour respecter toutes les restrictions que vous souhaitez.

insert into SLA_DEMANDE_STATUS 
    ( iddemande,
      idindicateur,
      indicateur_status,
      progression ) 
    SELECT 
         '0009' iddemande,
         c.id_criterere idindicateur,
         'OK' indicateur_status,
         10.0 progression
       FROM 
          indicateur i;
             JOIN critere c
                ON i.id_indicateur = c.id_indicateur
0
DRapp