mysql cursor 中使用循环(loop, 或者 repeat)时,循环每次会多执行一次。比如说,一次查询返回5条记录,使用cursor遍历时,循环会执行6次,当返回10条记录时,循环会遍历11次。出现这个现象的原因是,循环中的代码逻辑有点问题,稍加修改就能正常工作了。
先贴出有问题的代码:
DELIMITER //
CREATE PROCEDURE traverse_tables()
BEGIN
DECLARE tabnames_smsi varchar(50);
DECLARE smsi_done BOOLEAN DEFAULT 0;
DECLARE source_table_smsi CURSOR FOR SELECT DISTINCT smsi FROM module_name;
-- 定义循环结束条件
DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET smsi_done = 1;
-- 打开游标
OPEN source_table_smsi;
smsi_loop: REPEAT
FETCH source_table_smsi INTO tabnames_smsi;
select tabnames_smsi, smsi_done;
UNTIL smsi_done END REPEAT smsi_loop;
-- 关闭游标
CLOSE source_table_smsi;
END//
DELIMITER ;
当没有新的记录可供遍历时,SQLSATTE '02000'会出现,这时smsi_done变量会被置为1,此时还会再多执行select tabnames_smsi, smsi_done;一次,导致一个多余的循环。因此,需要首先在循环体中检查smsi_done这个变量的值,当为1时,跳出循环,不为1时才执行循环体。
改进后的代码:
DELIMITER //
CREATE PROCEDURE traverse_tables()
BEGIN
DECLARE tabnames_smsi varchar(50);
DECLARE smsi_done BOOLEAN DEFAULT 0;
DECLARE source_table_smsi CURSOR FOR SELECT DISTINCT smsi FROM module_name;
-- 定义循环结束条件
DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET smsi_done = 1;
-- 打开游标
OPEN source_table_smsi;
smsi_loop: REPEAT
FETCH source_table_smsi INTO tabnames_smsi;
IF NOT smsi_done THEN
select tabnames_smsi, smsi_done;
END IF;
UNTIL smsi_done END REPEAT smsi_loop;
-- 关闭游标
CLOSE source_table_smsi;
END//
DELIMITER ;
或者也可以这样写
DELIMITER //
CREATE PROCEDURE traverse_tables()
BEGIN
DECLARE tabnames_smsi varchar(50);
DECLARE smsi_done BOOLEAN DEFAULT 0;
DECLARE source_table_smsi CURSOR FOR SELECT DISTINCT smsi FROM module_name;
-- 定义循环结束条件
DECLARE CONTINUE HANDLER FOR SQLSTATE '02000' SET smsi_done = 1;
-- 打开游标
OPEN source_table_smsi;
smsi_loop: REPEAT
FETCH source_table_smsi INTO tabnames_smsi;
IF smsi_done THEN
-- 关闭游标
CLOSE source_table_smsi;
-- 跳出循环
LEAVE smsi_loop;
END IF;
select tabnames_smsi, smsi_done;
UNTIL smsi_done END REPEAT smsi_loop;
END//
DELIMITER ;