oracle和mysql的游标都有这个相同的问题,以Oracle说明,同样适用于mysql;
问题:
游标循环的最后一个会重复循环一次,错误如下:
现象:
【exit when 游标名称%not found】放置的位置不同会有不同的效果;
若放置在loop循环的末尾进行判断,则会导致重复;
若放置在loop循环的fetch取值之后,执行结构之前,就是正常的,不会重复;
想想为啥!?
分析:
游标循环判断的逻辑是对本次fetch进行数据有无的判断,而不是移动到下一个记性判断。
所以,本来最后一次后应退出结束循环,实际并没有,因为exit when 游标名称%not found判断的是本次fetch有没有数据,当然是有的,30呀,那么就会继续loop循环,下一次的循环赋值时fetch就没取到,那变量就没有被刷新赋值,所以保持着最后一次的变量值进行循环执行了语句,再到了最后的判断结构【exit when 游标名称%not found】判断时,此次的fetch是没有数据,就符合退出条件,所以就会结束循环,所以会导致游标的最后一行数据被重复循环一次。
本质:
不同放置位置的本质为:
【先判断后执行】 / 【先执行后判断】
解决:
按照 【先判断后执行】 去设置 【exit when 游标名称%not found】的放置位置 ;
既然exit是判断的当次的fetch有无数据,那么就先判断后执行,将判断结构放在具体的执行语句之前,保证当次fetch有数据才执行,不会重复;
CREATE OR REPLACE PROCEDURE SP_VSQL_CURSOR
AS
CURSOR CUR_DNO IS SELECT DEPTNO FROM DNO; -- DNO中仅一个字段,有10/20/30共3个数据
V_DNO NUMBER;
BEGIN
OPEN CUR_DNO;
LOOP
FETCH CUR_DNO INTO V_DNO;
EXIT WHEN CUR_DNO%NOTFOUND; -- 此时,为【先判断后执行】
INSERT INTO EMP_INSERT SELECT * FROM EMP WHERE DEPTNO=V_DNO;
END LOOP;
CLOSE CUR_DNO;
END;
/