#游标

游标(Cursor)被用于指向一条SQL语句一行或多行的结果集,提供在结果集中分行浏览数据的能力。

YashanDB中可由用户声明和使用的游标分为如下几种:

  • 显式游标:使用CURSOR...IS命令定义的游标,在其定义时静态绑定了一条SQL语句,不可更改与赋值。
  • 动态游标:使用TYPE...IS REF CURSOR定义的游标变量,可以与不同的SQL语句动态绑定(某一时刻只能与一条SQL语句绑定),只需要这些SQL语句的返回类型与游标变量定义的类型兼容即可。
  • sys_refcursor:系统预定义的动态游标类型,可直接调用,使用方法与动态游标一致。

分布式部署中不可使用游标变量,但支持使用隐式游标相关属性。

YashanDB在同一时间可打开的游标数目限制为300个。

游标所绑定的SQL中不能有FOR UPDATE语句。

游标的语句中使用了PL中变量等标识符在投影列时,需要指定别名用来后续访问。

# 显式游标

通过游标定义语句实现对显式游标的声明,之后即可在过程体中执行打开游标推进游标关闭游标等操作。

cursor_definition::=

syntax
CURSOR cursor ( cursor_parameters , ) RETURN rowtype IS select_statement ;

cursor_parameters

定义显式游标的参数,该参数用于给绑定的SQL语句提供变量输入,参数定义格式为:

参数名称 数据类型 [缺省值]

其中,数据类型里不应该包含长度、精度等属性。

可以为游标的参数定义一个缺省值,之后,允许在打开游标时不输入参数值,系统将会以此缺省值作为参数值传入,当仍输入参数值时,则会以输入的值作为参数值传入。

当游标的参数为多个时,应该将定义缺省值的参数放在最后面,但在使用"=>"传入参数值时,无需此顺序要求。

RETURN rowtype

定义显式游标的返回值,必须指定为一个RECORD类型变量,且其列项必须与绑定SQL语句的查询列项相匹配。

RETURN rowtype语句可省略,则系统将隐式地生成一个返回值变量,其列项即为绑定SQL语句的查询列项。

select_statement

SELECT查询语句,但不可包含FOR UPDATE,且不可指定占位符(绑定参数)。

示例(单机、共享集群部署)

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循环
DECLARE
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::=

syntax
TYPE type IS REF CURSOR RETURN table_or_view cursor cursor_variable %ROWTYPE record %TYPE record_type ;

cursor_variable_declaration::=

syntax
cursor_variable type ;

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参数使用:

  • 作为存储过程或自定义函数的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语句,或者其返回值列项与左值游标一致,则可赋值。
  • 存储过程/函数的IN、IN OUT游标实参,执行开始时会进行赋值规则检查,执行完成返回前会对OUT、IN OUT游标实参进行赋值规则检查。

示例(单机、共享集群部署)

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.