#游标
游标(Cursor)被用于指向一条SQL语句一行或多行的结果集,提供在结果集中分行浏览数据的能力。
YashanDB中可由用户声明和使用的游标分为如下几种:
- 显式游标:使用CURSOR...IS命令定义的游标,在其定义时静态绑定了一条SQL语句,不可更改与赋值。
- 动态游标:使用TYPE...IS REF CURSOR定义的游标变量,可以与不同的SQL语句动态绑定(某一时刻只能与一条SQL语句绑定),只需要这些SQL语句的返回类型与游标变量定义的类型兼容即可。
- sys_refcursor:系统预定义的动态游标类型,可直接调用,使用方法与动态游标一致。
分布式部署中不可使用游标变量,但支持使用隐式游标相关属性。
YashanDB在同一时间可打开的游标数目限制为300个。
游标不支持与FOR UPDATE语句组合使用。
# 显式游标
通过游标定义语句实现对显式游标的声明,之后即可在过程体中执行打开游标、推进游标、关闭游标等操作。
cursor_definition::=
cursor_parameters
定义显式游标的参数,该参数用于给绑定的SQL语句提供变量输入,参数定义格式为:
参数名称 数据类型 [缺省值]
其中,数据类型里不应该包含长度、精度等属性。
可以为游标的参数定义一个缺省值,之后,允许在打开游标时不输入参数值,系统将会以此缺省值作为参数值传入,当仍输入参数值时,则会以输入的值作为参数值传入。
当游标的参数为多个时,应该将定义缺省值的参数放在最后面,但在使用"=>"传入参数值时,无需此顺序要求。
RETURN rowtype
定义显式游标的返回值,必须指定为一个RECORD类型变量,且其列项必须与绑定SQL语句的查询列项相匹配。
RETURN rowtype语句可省略,则系统将隐式地生成一个返回值变量,其列项即为绑定SQL语句的查询列项。
select_statement
暂不支持投影列使用绑定参数。
示例
DECLARE
CURSOR cur(c1 CHAR) IS
SELECT area_no, area_name FROM area WHERE area_no=c1;
TYPE record1 IS RECORD (
c1 CHAR(2),
c2 VARCHAR(20)
);
rec record1;
BEGIN
OPEN cur(c1=>'01');
FETCH cur INTO rec;
DBMS_OUTPUT.PUT_LINE(rec.c1 ||' '||rec.c2);
CLOSE cur;
END;
/
--result
01 华东
-- 游标for循环
CREATE OR REPLACE PROCEDURE ya_proc
IS
CURSOR emp_cur IS SELECT * FROM employees;
BEGIN
DBMS_OUTPUT.PUT_LINE('EMPNO ENAME');
DBMS_OUTPUT.PUT_LINE('----- -------');
FOR v_emp_rec IN emp_cur LOOP
DBMS_OUTPUT.PUT_LINE(v_emp_rec.employee_no || ' ' || v_emp_rec.employee_name);
END LOOP;
END;
/
--result
EMPNO ENAME
----- -------
0101000001 Mask
0101000002 John
0201010011 Anna
0201008003 Jack
0201008004 Jim
# 动态游标
动态游标要求首先定义一个引用游标类型,并按此类型声明一个游标变量,之后即可在过程体中执行打开游标、游标取值、关闭游标等操作。
ref_cursor_type_definition::=
cursor_variable_declaration::=
RETURN子句
RETURN子句显示地定义了动态游标所持有的返回值,该返回值必须通过一个RECORD类型来记录,包括:
- %ROWTYPE引用的表、视图、显式游标或游标变量(必须为一个显式定义了返回值的游标变量)。
- %TYPE引用的一个已定义的RECORD类型变量。
- 一个已定义的RECORD类型变量。
打开游标的操作中,若被打开的SQL语句的查询列与此处RECORD所记录的成员无法进行隐式类型转换时,将无法对该SQL语句赋值给游标变量。
本语句可省略,此时声明的是一个没有指定结果集的游标变量,可以实现绑定不同的SQL语句且返回不同类型的RECORD。
示例
--未显式定义返回值的动态游标声明
DECLARE
TYPE cursor IS REF CURSOR;
cur cursor;
TYPE record1 IS RECORD (
c1 CHAR(2),
c2 VARCHAR(20)
);
rec1 record1;
TYPE record2 IS RECORD (
c1 CHAR(2),
c2 VARCHAR(20),
c3 INT
);
rec2 record2;
BEGIN
OPEN cur FOR SELECT area_no, area_name FROM area WHERE area_no='01';
FETCH cur INTO rec1;
DBMS_OUTPUT.PUT_LINE(rec1.c1 ||' '||rec1.c2);
CLOSE cur;
OPEN cur FOR SELECT area_no, area_name, LENGTH(area_name) FROM area WHERE area_no='01';
FETCH cur INTO rec2;
DBMS_OUTPUT.PUT_LINE(rec2.c1 ||' '||rec2.c2||' '||rec2.c3);
CLOSE cur;
END;
/
--result
01 华东
01 华东 2
--显式定义返回值的动态游标声明
DECLARE
TYPE cursor1 IS REF CURSOR RETURN area%ROWTYPE;
cur1 cursor1;
TYPE cursor2 IS REF CURSOR RETURN cur1%ROWTYPE;
cur2 cursor2;
TYPE record IS RECORD (
c1 CHAR(2),
c2 VARCHAR(20),
c3 VARCHAR(20)
);
rec record;
BEGIN
OPEN cur2 FOR SELECT * FROM area WHERE area_no='01';
FETCH cur2 INTO rec;
DBMS_OUTPUT.PUT_LINE(rec.c1 ||' '||rec.c2||' '||rec.c3);
CLOSE cur2;
END;
/
--result
01 华东 Shanghai
# sys_refcursor
sys_refcursor为系统预定义的不指定返回值的动态游标,可被直接用于游标变量的声明,其用法与动态游标一致。
游标参数
基于系统预定义的sys_refcursor,可以将游标作为PL/SQL参数使用:
- 作为存储过程或自定义函数的IN参数。
- 作为存储过程的OUT参数。
- 作为自定义函数的返回值。
示例
CREATE OR REPLACE PROCEDURE getArea(cur IN OUT SYS_REFCURSOR) AS
BEGIN
OPEN cur FOR SELECT * FROM area WHERE area_no='01';
END;
/
CREATE OR REPLACE FUNCTION getArea_func RETURN SYS_REFCURSOR AS
cur SYS_REFCURSOR;
BEGIN
OPEN cur FOR SELECT * FROM area WHERE area_no='02';
RETURN cur;
END;
/
DECLARE
TYPE record IS RECORD (
c1 CHAR(2),
c2 VARCHAR(20),
c3 VARCHAR(20)
);
rec record;
cur SYS_REFCURSOR;
BEGIN
cur := getArea_func;
FETCH cur INTO rec;
DBMS_OUTPUT.PUT_LINE(rec.c1 ||' '||rec.c2||' '||rec.c3);
CLOSE cur;
getArea(cur);
FETCH cur INTO rec;
DBMS_OUTPUT.PUT_LINE(rec.c1 ||' '||rec.c2||' '||rec.c3);
CLOSE cur;
END;
/
--result
02 华西 Chengdu
01 华东 Shanghai
# 游标间赋值
YashanDB支持直接将一个游标变量赋值给另一个游标变量,规则如下:
- 显式游标无法作为任何赋值表达式的左值或右值。
- 两个返回值列项相同的动态游标可相互赋值。
- 无返回值的游标作为左值时可被任意非显式游标赋值。
- 有返回值的游标作为左值时将会判断右值游标的返回值列项,若右值游标未绑定SQL语句,或者其返回值列项与左值游标一致,则可赋值。
示例
DECLARE
cur0 SYS_REFCURSOR;
TYPE cursor IS REF CURSOR RETURN area%ROWTYPE;
cur cursor;
TYPE record IS RECORD (
c1 CHAR(2),
c2 VARCHAR(20),
c3 VARCHAR(20)
);
rec record;
BEGIN
OPEN cur FOR SELECT * FROM area WHERE area_no='01';
cur0 := cur;
FETCH cur0 INTO rec;
DBMS_OUTPUT.PUT_LINE(rec.c1 ||' '||rec.c2||' '||rec.c3);
CLOSE cur;
END;
/
--result
01 华东 Shanghai
# 游标的属性
游标有四个属性,如下:
属性 | 返回值类型 | 作用 |
---|---|---|
%isopen | 布尔型 | 判断游标是否打开 |
%found | 布尔型 | 判断游标是否获取到值 |
%notfound | 布尔型 | 判断游标是否没有获取到值 |
%rowcount | BIGINT | 当前成功执行的数据行数 |
上述属性只能在过程性语句中使用,不能使用在SQL语句中,使用格式如下:
cursor_name%isopen、cursor_name%found、cursor_name%notfound、cursor_name%rowcount
其中cursor_name为游标的名称,使用示例可查看FETCH Statement。
隐式游标属性
在过程体中执行某条SQL语句时,系统为其生成了一个隐式的游标,隐式游标无需用户声明和管理,但用户可以通过上述游标属性来操作其结果集,使用格式如下:
SQL%isopen、SQL%found、SQL%notfound、SQL%rowcount
示例
BEGIN
UPDATE area SET area_name='cursor example';
IF SQL%found THEN
DBMS_OUTPUT.PUT_LINE('Total '||SQL%rowcount||' lines are deleted.');
END IF;
ROLLBACK;
END;
/
--result
Total 5 lines are deleted.