我们在使用储存过程中使用游标遍历数据的时候的基本写法如下:
create procedure proc_test() sql security invokerbegin declare p_id varchar(32); declare done tinyint default false; declare c_cur cursor for select id from user; declare continue handler for not found set done = true; open c_cur; fetch c_cur into p_id; while !done do ... #程序逻辑 fetch c_cur into p_id; end while; close c_cur;end;
正常情况这么写是没问题的,可是如果你在while里面的要是有select语句的话就有问题了。如果说你的处理逻辑是这样的:
while !done do select * from user_role r where r.user_id = p_id; fetch c_cur into p_id; end while;
那么当你的select * from user_role r where r.user_id = p_id;找不到数据的时候,declare continue handler for not found set done = true;这句就会执行,有done = true,所以循环体会提前跳出。通过测试得出,declare continue handler for not found set done = true 是对全局的select有效的,只要有一条select语句返回空,那么就是触发该语句。
解决方法就是确保while里面的select永远不会返回空
select * from user_role r where r.user_id = p_id;#改成下面这样select col1, col2, ... from(select col1, col2, ... from user_role r where r.user_id = p_idunion allselect '' col1, '' col2, ...) t
这样的话就可以保证select肯定不是空集合。