web-dev-qa-db-ja.com

MySQLのネストされたループ内の複数のカーソル

MySQLでは少し複雑に見えることをしたいと思います。実際、カーソルを開いてループを実行し、このループで、実行する前のフェッチのデータを使用して2番目のカーソルを開き、結果を再度ループしたいと思います。

  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;

実際、SQLSTATEに対して宣言できるハンドラーは1つだけなので、2つのカーソルに対して「Untildone」を異なる方法で実行するにはどうすればよいですか?最初が終了すると、2番目も終了します。

15
user5537

最初のカーソルループ内に新しいブロックを定義し、そのブロックで異なる宣言を使用する必要があります。

何かのようなもの:

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

または、CONTINUEHANDLEを再定義します。

//...
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;          

ループ内のすべてのselectステートメントがCONTINUEHANDLEを実行しているようです

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

次のように、ループを使用して、ハンドルの値をリセットできます。

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

私が間違っている場合は訂正してください。しかし、あなたがやろうとしているのは、「SLA_DEMANDE_STATUS」テーブルへのレコードの一括挿入であるようです。見つかったすべてのインジケーターのすべての基準を含め、各インジケーターの基準IDごとに「0009」、「OK」、および10.0の値でデフォルト設定します。

これはすべて、単一のSQL-Insertで実行できます。 INSERT INTO ... SQLから-選択...

ここで、単一の「id_indicateur」エントリのみを含めたい場合は、それをselectステートメントのWHERE句に追加できます。

私のSQL-Selectは、入力したい列に対応するように値を強制していることに注意してください。それらはすべて同じ名前で宛先テーブルに挿入されます。これの良いところは、SQL-SELECT部分​​を実行して、挿入されると予想されるデータを確認することです。正しくない場合は、必要な制限に合うように調整できます。

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