存储过程的一般结构如下:
CREATE PROCEDURE testDynamicCursor(IN flag CHAR(1)) --首句定义名称及参数
BEGIN --开始
DECLARE v_sql VARCHAR(1000); --定义变量
DECLARE v_st STATEMENT;
DECLARE v_cursor CURSOR WITH RETURN FOR v_st; -- 定义游标(不同的数据库写法可能不一样)
--下面是处理过程(处理过程里面也可以继续定义变量或游标,继续处理)
IF (flag = '1') THEN
SET v_sql = 'SELECT * FROM TEST1';
ELSE
SET v_sql = 'SELECT * FROM TEST2';
END IF;
PREPARE v_st FROM v_sql;
OPEN v_cursor;
END --结束
使用存储过程的难点在于游标的使用,本文着重介绍游标的使用。
使用游标对记录集循环进行处理的时候一般操作如以下几个步骤:
1、把记录集传给游标(定义游标)
2、打开游标
3、开始循环
4、从游标中取值
5、检查那一行被返回
6、处理
7、关闭循环
8、关闭游标
一、ORCAL的游标
1.其游标的遍历有两种:
⑴For 循环游标
循环游标隐式打开游标,自动滚动获取一条记录,并自动创建临时记录类型变量存储记录。处理完后自动关闭游标。
For 变量名 In 游标名
Loop
数据处理语句;
End Loop;
⑵Loop循环游标
。。。
Loop
Fatch 游标名InTo 临时记录或属性类型变量;
Exit When 游标名%NotFound;
End Loop;
实例:
loop遍历:
Declare
Cursor myCur is select ename,job,sal,empno from emp;
varE myCur%rowType;
Begin
if myCur%isopen = false then
open myCur;
dbms_output.put_line('Opening...');
end if;
loop
fetch myCur into varE;
exit when myCur%notfound;
dbms_output.put_line(myCur%rowCount||' '||vare.empno||' '||vare.ename||' '||vare.sal);
end loop;
if myCur%isopen then
Close myCur;
dbms_output.put_line('Closing...');
end if;
End;
for遍历:
Declare
Cursor myCur is select * from emp;
Begin
for varA in myCur
loop
dbms_output.put_line(myCur%rowCount||' '||varA.empno||' '||varA.ename||' '||varA.sal);
end loop;
End;
二、DB2游标
有两种定义方式:
注意 commit和rollback
使用游标时要特别注意如果没有加with hold 选项,在Commit和Rollback时,该游标将被关闭。Commit 和Rollback有很多东西要注意。特别小心。
1.第一种
declare continue handler for not found
begin
set v_notfound = 1;
end;
declare cursor1 cursor with hold for select market_code from tb_market_code for update;
open cursor1;
set v_notfound=0;
fetch cursor1 into v_market_code;
while v_notfound=0 Do
--work
set v_notfound=0;
fetch cursor1 into v_market_code;
end while;
close cursor1;
这种方式使用起来比较复杂,但也比较灵活。特别是可以使用 with hold 选项。如果循环内有commit或rollback 而要保持该cursor不被关闭,只能使用这种方式。
注:实际上这种还有些复杂,可以简化:
begin
declare ....... --定义游标;
open .... ---开启游标;
while .... do
fetch cursor1 into v_market_code;
----work;
<!-- 另一个游标 start -->
p1:begin
declare ......
.......
end p1;
<!-- 另一个游标 end -->
end while;
colse .... --关闭游标
end;
2.第二种
pcursor1: for loopcs1 as cousor1 cursor as
select market_code as market_code
from tb_market_code
for update
do
end for;
这种方式的优点是比较简单,不用(也不允许)使用 open,fetch,close。
但不能使用with hold 选项。如果在游标循环内要使用commit,rollback则不能使用这种方式。如果没有commit或rollback的要求,推荐使用这种方式(看来For这种方式有问题)。
修改游标的当前记录的方法
update tb_market_code set market_code='0' where current of cursor1;
不过要注意将cursor1定义为可修改的游标
declare cursor1 cursor for select market_code from tb_market_code
for update;
for update 不能和 GROUP BY、 DISTINCT、 ORDER BY、 FOR READ ONLY及UNION, EXCEPT, or INTERSECT 但 UNION ALL除外)一起使用。
实例:
CREATE OR REPLACE PROCEDURE "WGHYXXM_2"."PROC_SQL_ADDR"
()
LANGUAGE SQL
SPECIFIC SQL191014013422827
BEGIN
--特别注意:过程中循环游标时,while语句就是循环,所以要去掉loop
declare np_addrs VARCHAR(30);
declare rel_org VARCHAR(30);
declare p_addrs cursor with hold FOR SELECT cust_id from GD_P_CUST_ADDR_HIS where cust_location_bd is NULL;
open p_addrs;
-- LOOP
fetch p_addrs into np_addrs; --所有地址为空的客户
while np_addrs is not null DO
begin
DECLARE rel_loc_db CURSOR for SELECT BRANCH_ID from GD_P_CUST_MANGER_BRANCH_REL where CUST_ID = np_addrs;
open rel_loc_db;
-- LOOP
fetch rel_loc_db into rel_org;
while rel_org is not null DO
begin
declare cust_dbx NUMERIC ;
declare cust_dby NUMERIC;
declare loc_dbs cursor with hold for SELECT db2gse.st_x(LOCATION_BD) , db2gse.st_y(LOCATION_BD) from FND_BANK_INFO where ORG_ID = rel_org;
open loc_dbs;
-- LOOP
fetch loc_dbs into cust_dbx , cust_dby;
while cust_dbx is not null do
BEGIN
UPDATE GD_P_CUST_ADDR_HIS set CUST_LOCATION_BD = db2gse.st_POINT(cust_dbx , cust_dby,1) where CUST_ID = np_addrs;
end;
end while;
-- end loop;
close loc_dbs;
end;
end while;
-- end loop;
close rel_loc_db;
end;
end while;
-- end LOOP;
close p_addrs;
END
-- CALL dbms_output.put_line('111'); 这是打印输出
-- execute test_select3_procedure('XXX'); 执行存储过程