如何在MySQL中的单个存储过程中使用多个游标

时间:2012-07-05 04:53:47

标签: mysql cursor

我想创建一个能够执行多任务的存储过程。然后它收到错误消息

Error Code: 1338 Cursor declaration after handler declaration

请查看我的商店程序

CREATE PROCEDURE `spTest`(OUT v1 VARCHAR(500), OUT v2 VARCHAR(500))
BEGIN

    DECLARE  _cur_1 CURSOR FOR
        SELECT id
        FROM tbl_1;
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET _cur1Done = 1;

    DECLARE  _cur_2 CURSOR FOR
        SELECT id
        FROM tbl_2;
    DECLARE CONTINUE HANDLER FOR NOT FOUND SET _cur2Done = 1;

    .......

2 个答案:

答案 0 :(得分:3)

manual中说

  

游标声明必须出现在处理程序声明之前以及变量和条件声明之后。

另外你不能有多个继续处理程序(MySQL应该如何知道哪个继续处理程序与哪个游标有关?不幸的是你不能指定它),除非你嵌套它们,例如像这样:

DELIMITER $$
CREATE PROCEDURE `spTest`(OUT v1 VARCHAR(500), OUT v2 VARCHAR(500))
BEGIN
BLOCK1:BEGIN

    DECLARE variable1 INT;

    DECLARE  _cur_1 CURSOR FOR SELECT id FROM tbl_1;

    DECLARE CONTINUE HANDLER FOR NOT FOUND SET _cur1Done = 1;
    LOOP1: LOOP
    FETCH _cur_1 INTO variable1;
    IF _cur1Done THEN 
        CLOSE _cur_1;
        LEAVE LOOP1;
    END IF;

    BLOCK2:BEGIN

        DECLARE variable2 INT;

        DECLARE  _cur_2 CURSOR FOR SELECT id FROM tbl_2;

        DECLARE CONTINUE HANDLER FOR NOT FOUND SET _cur2Done = 1;

        OPEN _cur_2;
        LOOP2: LOOP

            FETCH _cur_2 INTO variable2;
            IF _cur2Done THEN
                CLOSE _cur_2;
                LEAVE LOOP2;
            END IF;
        END LOOP LOOP2;
    END BLOCK2;
END LOOP LOOP1;
END BLOCK1;
END $$
DELIMITER ;

答案 1 :(得分:3)

你可能只有一个continue handler活跃在一个区块中。即使您获得了正确的声明顺序(首先是所有游标,然后是处理程序),多个continue handler会出现Duplicate handler declared in same block问题。

您可以通过创建专门用于游标访问的块来解决此问题。您可以将这些代码块放在同一个父块中,也可以放在嵌套循环中,或者放在任何地方。

DELIMITER $$
CREATE PROCEDURE `spTest`(OUT v1 VARCHAR(500), OUT v2 VARCHAR(500))
BEGIN

    declare tbl_1_id int;
    declare tbl_2_id int;

    declare _cur1Done boolean default false;
    declare _cur2Done boolean default false;

    DECLARE  _cur_1 CURSOR FOR SELECT id FROM tbl_1;
    DECLARE  _cur_2 CURSOR FOR SELECT id FROM tbl_2;

    begin -- dedicated block to fetch from cursor 1 and update its flag
        declare continue handler for not found set _cur1Done = TRUE;
        fetch _cur_1 into tbl_1_id;
    end;

    begin -- dedicated block to fetch from cursor 2 and update its flag
        declare continue handler for not found set _cur2Done = TRUE;
        fetch _cur_2 into tbl_2_id;
    end;
END $$
DELIMITER ;