使用带游标的预准备语句

时间:2014-02-16 10:40:33

标签: mysql sql

我将游标声明放在预准备语句中,然后执行它,然后返回error #1324 - Undefined CURSOR: getid.

如何解决这个问题?

delimiter ;;

drop procedure if exists test2;;

create procedure test2(table_id VARCHAR(25))
BEGIN
    DECLARE done INT DEFAULT FALSE;
    DECLARE id INT;
    DECLARE id_new INT;
    DECLARE stmt1 VARCHAR(1024);
    DECLARE stmt2 VARCHAR(1024);
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET done = 1;

    SET @sqltext1 := CONCAT('DECLARE getid CURSOR FOR SELECT entryId FROM ',table_id,' ORDER BY entryId');
    PREPARE stmt1 FROM @sqltext1;
    EXECUTE stmt1;

    SET @id_new = 1; 

    OPEN getid;

    FETCH getid into id;
    REPEAT
        SET @sqltext2 := CONCAT('UPDATE ',table_id,' SET entryId = ? WHERE entryId = ?');
        PREPARE stmt2 FROM @sqltext2;
        EXECUTE stmt2 USING @new_id, id;
        SET @id_new = @id_new + 1;
        FETCH getid into id;
    UNTIL done END REPEAT;
    CLOSE getid;
END
;;

CALL test2('Test');

1 个答案:

答案 0 :(得分:4)

一些规则:

  1. 所有声明必须位于序列中的一个位置。
  2. 您无法在游标声明中使用变量名称。
  3. 处理程序声明必须在游标声明之后。
  4. 您不能将局部变量名称(id)用作绑定参数 准备好的陈述您只能使用session个变量(例如@_id)。
  5. 要克服这些问题,您可以采用以下解决方案。

    1. 使用SP的输入参数定义临时表。
    2. 现在将光标声明在同一个表上并使用它。
    3. 删除创建的临时表。
    4. 以下示例应该适用于您的表。

      delimiter $$
      
      drop procedure if exists test2$$
      
      create procedure test2( table_id varchar(25) )
      begin
        set @temp_query = 'drop temporary table if exists temp_cursor_table';
        prepare pst from @temp_query;
        execute pst;
        drop prepare pst; -- or
        -- deallocate prepare pst;
      
        set @temp_table_query='create temporary table temp_cursor_table ';
        set @temp_table_query=concat( @temp_table_query, ' select entryId from ' );
        set @temp_table_query=concat( @temp_table_query, table_id );
        set @temp_table_query=concat( @temp_table_query, ' order by entryId' );
      
        prepare pst from @temp_table_query;
        execute pst;
        drop prepare pst;
      
        -- now write your actual cursor and update statements
        -- in a separate block
        begin
          declare done int default false;
          declare id int;
          declare id_new int;
          declare stmt1 varchar(1024);
          declare stmt2 varchar(1024);
      
          declare getid cursor for  
                    select entryId from temp_cursor_table order by entryId;
          declare continue handler for not found set done = 1;
      
          set @id_new = 1; 
      
          open getid;
          fetch getid into id;
          repeat
            set @sqltext2 := concat( 'update ', table_id );
            set @sqltext2 := concat( @sqltext2, ' set entryId = ? where entryId = ?' );
            set @_id = id;
            prepare stmt2 from @sqltext2;
            execute stmt2 using @new_id, @_id;
            set @id_new = @id_new + 1;
            fetch getid into id;
          until done end repeat;
          close getid;
        end;
      end;
      $$
      
      delimiter ;
      

      现在使用table_id值调用该过程。

      call test2( 'Test' );