2011-05-23 124 views
14

Deseo hacer algo que parece un poco complicado en MySQL. De hecho, deseo abrir un cursor, hacer un bucle, y en este bucle, abrir un segundo cursor usando los datos de la búsqueda anterior para ser ejecutado, y volver a repetir los resultados.Varios cursores en bucles anidados en MySQL

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; 

De hecho, la forma de hacerlo 'hasta que esté hecho' de forma diferente para los dos cursores, porque sólo se puede declarar un manejador para SQLSTATE? Si la primera termina, la segunda termina también.

+2

Th at es casi siempre la forma incorrecta de hacer las cosas, y posiblemente ineficaz para arrancar. Combina las dos operaciones de selección en una declaración (y, por lo tanto, usa solo un ciclo); normalmente será más eficiente. –

+0

Tiene una tasa baja. Importante en SO, debe marcar las respuestas aceptadas utilizando la marca de la izquierda de la respuesta publicada, debajo de la votación. Esto aumentará tu tasa. Vea cómo funciona esto visualizando este enlace: http://meta.stackoverflow.com/questions/5234/how-does-accepting-an-answer-work#5235 – Pentium10

Respuesta

22

Necesita definir un nuevo BLOQUE dentro de su 1er bucle de cursor y usar diferentes declaraciones en ese bloque.

Algo así como:

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; 
+0

gracias por compartir –

0

me corrija si estoy equivocado, pero parece que lo que está tratando de hacer es una inserción masiva de registros en la tabla "SLA_DEMANDE_STATUS". Incluya todos los criterios para cada indicador encontrado y por defecto con los valores de '0009', 'OK' y 10.0 por cada ID de criterio de cada indicador.

Todo esto se puede hacer en una sola inserción SQL. INSERT INTO ... de un SQL-Select ...

Ahora, si solo desea incluir una sola entrada "id_indicateur", puede agregar eso a la cláusula WHERE de la instrucción select.

Observe que mi SQL-Select ha obligado a los valores a corresponderse con las columnas que desea rellenar. Todos se insertarán en la tabla de destino con el mismo nombre. Lo bueno de esto es que solo puedes ejecutar la porción SQL-SELECT solo para ver los datos que ESPERA tener insertados ... si es incorrecta, puedes ajustarla para que se ajuste a las restricciones que quieras.

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

podría utilizar bucle y restablecer el valor del mango, así:

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

O redefinir el CONTINUAR MANGO:

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

Parece que todas las instrucciones select en el interior un ciclo ejecuta el CONTINUAR HANDLE

0
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

Rodear su código por alguna explicación sería considerado bonito, – zx485

Cuestiones relacionadas