#FOR Statement
FOR Statement为循环控制语句,其语法形式分为普通用法和for cursor用法两种。
# 普通用法
for counter in [reverse] lower_bound .. upper_bound loop
......
end loop [label_name];
其中,counter为计数器,lower_bound为计数器下限值,upper_bound为计数器上限值;reverse为控制参数,使用此参数表示将计数器从默认的递增改为递减模式。
counter、lower_bound、upper_bound均为BIGINT类型,取值范围同BIGINT值域。
label_name为可选项,作为一个标签(Label)标识循环体,提升可读性,使用label_name需在循环体开始处有相匹配的标签定义,否则将报错。
# counter
counter为FOR Statement里隐式声明的局部变量,只能在FOR语句内部使用,不可被继承类型,退出FOR语句后失效。
counter可以与过程体全局变量、或者其他循环控制语句内部的局部变量重名,此时 :
- 在FOR Statement内部,counter表示的是本语句局部变量,且只能由_for counter in [reverse] lower_bound .. upper_bound loop_对其赋值。
- 当需要在FOR Statement内部访问其他的同名变量时,必须使用标签.counter来识别,标签的描述参见GOTO Statement。
# lower_bound|upper_bound
lower_bound和upper_bound可以为常量或变量,以默认递增模式说明如下:
- 当lower_bound<upper_bound时,从lower_bound开始循环赋值到counter,一直到upper_bound结束循环语句;
- 当lower_bound=upper_bound时,lower_bound赋值到counter,循环语句只会执行一次;
- 当lower_bound>upper_bound时,直接跳转到END LOOP结束循环语句。
示例
<<G>>
DECLARE
i INT :=5;
BEGIN
<<F1>>
FOR i IN 1..9 LOOP
IF i>5 THEN
DBMS_OUTPUT.PUT_LINE(G.i); --访问过程体的全局变量
DBMS_OUTPUT.PUT_LINE(i || ':hello');
ELSE
FOR i IN 1..2 LOOP
DBMS_OUTPUT.PUT_LINE(F1.i); --访问上一级FOR语句的局部变量
DBMS_OUTPUT.PUT_LINE(i || ':world');
END LOOP;
END IF;
END LOOP;
END;
/
--result
1
1:world
1
2:world
2
1:world
2
2:world
3
1:world
3
2:world
4
1:world
4
2:world
5
1:world
5
2:world
5
6:hello
5
7:hello
5
8:hello
5
9:hello
DECLARE
BEGIN
FOR i IN 1..3 LOOP
DBMS_OUTPUT.PUT_LINE('loop:'||i);
END LOOP;
END;
/
--result
loop:1
loop:2
loop:3
# for 隐式游标用法
for counter in (select xx from table) loop
......
end loop [label_name];
其中, counter为隐式声明的局部变量,类型为其后的SELECT查询生成的默认RECORD类型,RECORD成员类型与SELECT查询列的类型一致,RECORD成员个数为查询列个数,不可被继承类型。
本用法为FOR循环支持隐式游标的用法,执行过程为每次循环时,FETCH查询语句的一行数据,将其填充到RECORD类型的counter,直到FETCH数据结束,循环也相应结束。
语句中使用了PL中变量等标识符在投影列时,需要指定别名用来后续访问。
示例
--SELECT查询
DECLARE
resultStr VARCHAR(200);
BEGIN
FOR file IN (SELECT area_no,area_name FROM area WHERE ROWNUM<5) LOOP
resultStr := resultStr||file.area_no||file.area_name;
DBMS_OUTPUT.PUT_LINE(resultStr);
END LOOP;
DBMS_OUTPUT.PUT_LINE(resultStr);
END;
/
--result
01华东
01华东02华西
01华东02华西03华南
01华东02华西03华南04华北
01华东02华西03华南04华北
# for 显式游标用法
for counter in cursor_x[()] loop
......
end loop [label_name];
其中, cursor_x为一个已定义的显式游标,包括本地定义和全局定义显式游标,支持有参数和无参数。
此处的显式游标用法与正常使用显式游标一致,counter为隐式声明的局部变量,类型为其后的显式游标查询生成的默认RECORD类型,RECORD成员类型与显式查询列的类型一致,RECORD成员个数为查询列个数,不可被继承类型。
本用法为for循环支持显式游标的用法,执行过程为:在for循环的第一次隐式调用显式游标的open操作,之后每次循环隐式调用显式游标的fetch操作,循环结束时隐式调用显式游标的close操作。在for循环体中不允许显式调用作为索引的显式游标的open/fetch/close操作,否则均做报错处理。
示例
-- 显式游标无参数
DECLARE
CURSOR c1 IS SELECT * FROM area ORDER BY area_no;
resultStr VARCHAR(200);
BEGIN
FOR v_sal IN c1 LOOP
resultStr := resultStr||v_sal.area_no||v_sal.area_name;
DBMS_OUTPUT.PUT_LINE(resultStr);
END LOOP;
END;
/
--result
01华东
01华东02华西
01华东02华西03华南
01华东02华西03华南04华北
01华东02华西03华南04华北05华中
-- 显式游标有参数
DECLARE
CURSOR c1(id INT) IS SELECT branch_no,branch_name FROM branches WHERE area_no = id ORDER BY branch_no;
resultStr VARCHAR(200);
BEGIN
FOR v_sal IN c1(1) LOOP
resultStr := resultStr||v_sal.branch_no||v_sal.branch_name;
DBMS_OUTPUT.PUT_LINE(resultStr);
END LOOP;
END;
/
--result
0101上海
0101上海0102南京
0101上海0102南京0103福州
0101上海0102南京0103福州0104厦门