目录
问题:
游标中, 如果 select 没有记录,游标提前退出(即使游标没有遍历完也会退出)。
原因:
declare continue handler for not found set done = true 是对全局的select有效的,只要有一条select语句返回空,那么就是触发该语句。
问题复现:
例 :如 select 没有数据的时候,就会执行:
declare continue handler for not found set done = true; done = true,所以循环体会提前跳出。
create procedure proc_test() sql security invoker
begin
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 = 1;
open c_cur;
fetch c_cur into p_id;
while !done do
select a into b from user_role r where r.user_id = p_id;
fetch c_cur into p_id;
end while;
close c_cur;
end;
解法一:
循环结束后加上set done = 0 ;完整版例子:
delimiter $$
create procedure test()
declare tmp_ia integer;
declare tmp_ib integer;
declare done integer default 0;
#将所有变量存在cur_test 中
declare cur_test cursor for
select
sum(a.ia),
sum(b.ib)
from
a_test a,
b_test b
where
a.id=b.id;
declare continue handler for not found set done = 1;
#打开游标,查询出的值依次插入变量tmp_ia和tmp_ib
open cur_test;
test_loop:loop
fetch next from cur_test into tmp_ia, tmp_ib;
if done then
leave test_loop;
end if;
#插入到结果表中
replace into r_test(
ia,
ib)
values(
tmp_ia,
tmp_ib
);
end loop test_loop;
close cur_test;
set done = 0;
end $$
delimiter ;
解法二:
采用set 赋值语句,适合查询少量的字段。
set b = (select a from test);
解法三:
select if 语句,适合少量数据:
用法:select if(条件,表达式1,表达式2);
注意:条件为真(非0),则返回表达式1,条件为假(0)返回表达式2,如select if(-1,5,2),返回值是5。如果select 多个数据的时候, if条件判断写需要一一对其类型,比较麻烦。多值数据不推荐。
select 中有聚合函数,用法:
select if (sum(a) != '', sum(a), '') from test
结果
+------------------------------------------+
| if (sum(a) != '', sum(a), '') |
+------------------------------------------+
| |
+------------------------------------------+
select中没有聚合函数,可以采用select if count语句 语句比如:
select if(count(a)>0,count(a),'') from test where a=11;
结果:
+----------------------------+
| if(count(a)>0,count(a),'') |
+----------------------------+
| |
+----------------------------+
select if(count(a)>0,count(a),'kong') from test where a=11;
结果
+--------------------------------+
| if(count(a)>0,count(a),'kong') |
+--------------------------------+
| kong |
+--------------------------------+
解法四:
因为当select· into赋值结果为null的时候,会自动修改循环触底的标志,
所以手动在循环底部增加 set no_more = 0 这样也可以避免提前退出循环,
注意set no_more = 0要放在 放在每次循环里面,即end loop之前