2011-10-07 13 views
10

Me gustaría utilizar LIMIT en un cursor. El cursor se debe usar y actualizar varias veces dentro de un ciclo, cada vez con diferentes parámetros de LIMIT. Aquí algo de código:Cursor dinámico en el procedimiento almacenado

DELIMITER $$ 
CREATE PROCEDURE `updateIt`() READS SQL DATA 
BEGIN 

declare done int(1) default 0; 
declare counter int(10) default 0; 
declare xabc int(10) default 0; 

declare tab1Cursor cursor for select abc from tab1 limit 100000*counter, 100000; 
declare continue handler for not found set done=1; 

loopCounter: LOOP 
    set done = 0; 
    open tab1Cursor; 
    igmLoop: loop 
     fetch tab1Cursor into xabc; 
     if done = 1 then leave igmLoop; end if; 
     -- do something 
    end loop igmLoop; 
    close tab1Cursor; 

    if (counter = 1039) 
     leave loopCounter; 
    end if; 
    set counter = counter + 1; 

END LOOP loopCounter; 
END $$ 
DELIMITER ; 

Sin embargo, esto no funciona (también he probado con el cursor en el bucle counterLoop). ¿Puede Mysql lidiar con cursores dinámicos?

Respuesta

11

Desde el MySQL Manual

un cursor no puede ser utilizado para una sentencia dinámica que se prepara y ejecuta con preparar y ejecutar. La instrucción para un cursor es marcada en el momento de creación del cursor, por lo que la instrucción no puede ser dinámica.

Sin embargo, hay 2 formas.

El primero es para casos en los que solo un usuario a la vez ejecutará el procedimiento. Se puede usar una declaración de preparación para crear una vista con el SQL dinámico y el cursor puede seleccionar desde esta vista con nombre estadístico. Casi no hay impacto en el rendimiento. Desafortunadamente, estas vistas también son visibles para otros usuarios (no existe una vista temporal), por lo que esto no funcionará para múltiples usuarios.

Análogamente, se puede crear una tabla temporal en la instrucción de preparación y el cursor puede seleccionar desde la tabla temporal. Solo la sesión actual puede ver una tabla temporal, por lo que se resuelve el problema de múltiples usuarios. Pero esta solución puede tener un impacto significativo en el rendimiento, ya que se debe crear una tabla temporal cada vez que se ejecuta el proceso.

Conclusión: ¡Todavía necesitamos cursores para poder crear dinámicamente!

Aquí hay un ejemplo del uso a fin de pasar el nombre de la tabla y el nombre de la columna en un cursor de la mysql forums

DELIMITER // 
DROP PROCEDURE IF EXISTS test_prepare// 

CREATE PROCEDURE test_prepare(IN tablename varchar(255), columnname varchar(50)) 
BEGIN 
DECLARE cursor_end CONDITION FOR SQLSTATE '02000'; 
DECLARE v_column_val VARCHAR(50); 
DECLARE done INT DEFAULT 0; 
DECLARE cur_table CURSOR FOR SELECT * FROM test_prepare_vw; 
DECLARE CONTINUE HANDLER FOR cursor_end SET done = 1; 

SET @query = CONCAT('CREATE VIEW test_prepare_vw as select ', columnname, ' from ', tablename); 
select @query; 
PREPARE stmt from @query; 
EXECUTE stmt; 
DEALLOCATE PREPARE stmt; 

OPEN cur_table; 
FETCH cur_table INTO v_column_val; 
WHILE done = 0 DO 
SELECT v_column_val; 
FETCH cur_table INTO v_column_val; 
END WHILE; 
CLOSE cur_table; 

DROP VIEW test_prepare_vw; 

END; 
// 

DELIMITER ; 
+0

Gracias. Eso podría funcionar para mi problema. Intento esto – Marcus

+1

miles de agradecimientos @ Pentium10 – gca

+1

La mayor parte de esta respuesta parece plagiarse en http://forums.mysql.com/read.php?61,116597,226041 Tal vez sea apropiada la atribución adecuada. – Rob

Cuestiones relacionadas