达梦数据库-游标简介

DMSQL 程序中使用 SELECT…INTO 语句将查询结果存放到变量中进行处理的方法,但这种方法只能返回一条记录,否则就会产生 TOO_MANY_ROWS 错误。为了解决这个问题,DMSQL 程序引入了游标,允许程序对多行数据(结果集)进行逐条处理

DM 游标分为静态游标和动态游标两类
游标和游标变量的关系就是常量和变量的关系
引用游标是一种特殊类型的游标变量

静态游标

静态游标是只读游标,它总是按照打开游标时的原样显示结果集,在编译时就能确定静态游标使用的查询
静态游标又分为两种:隐式游标和显式游标

隐式游标

隐式游标无需用户进行定义,每当用户在 DMSQL 程序中执行一个 DML 语句(INSERT、UPDATE、DELETE)或者 SELECT …INTO 语句时,DMSQL 程序都会自动声明一个隐式游标并管理这个游标。
隐式游标的名称统一称为“SQL”,用户可以通过隐式游标获取语句执行的一些信息

使用隐式游标的步骤

数据库自动执行隐式游标的相关操作。比如:打开游标、提取数据,关闭游标等

隐式游标的属性

DMSQL 程序中的每个游标都有%FOUND、%NOTFOUND、%ISOPEN 和%ROWCOUNT四个属性。但是隐式游标和显式游标的属性意义不同。对于隐式游标,这四个属性的意义如下:
%FOUND:语句是否修改或查询到了记录,是返回 TRUE,否则返回 FALSE;
%NOTFOUND:语句是否未能成功修改或查询到记录,是返回 TRUE,否则返回FALSE;
%ISOPEN:游标是否打开。是返回 TRUE,否返回 FALSE。由于系统在语句执行完成后会自动关闭隐式游标,因此隐式游标的%ISOPEN 属性永远为 FALSE;
%ROWCOUNT:DML 语句执行影响的行数,或 SELECT…INTO 语句返回的行数

示例,将孙丽的电话号码修改为 13818882888。示例中的“SQL”为隐式游标的名称:

BEGIN
	UPDATE PERSON.PERSON SET PHONE=13818882888 WHERE NAME='孙丽';
	IF SQL%NOTFOUND THEN
		PRINT '此人不存在';
	ELSE
		PRINT '已修改';
	END IF;
END;
/

显式游标

显式游标指向一个查询语句执行后的结果集区域。当需要处理返回多条记录的查询时,应显式地定义游标以处理结果集的每一行。

使用显式游标的步骤

使用显式游标一般包括四个步骤:

  1. 定义游标:在 DMSQL 程序的声明部分定义游标,声明游标及其关联的查询语句;
  2. 打开游标:执行游标关联的语句,将查询结果装入游标工作区,将游标定位到结果集的第一行之前;
  3. 拨动游标:根据应用需要将游标位置移动到结果集的合适位置,获取数据;
  4. 关闭游标:游标使用完后应关闭,以释放其占有的资源。
定义显式游标

在 DMSQL 程序的声明部分定义显式游标

CURSOR <游标名> [FAST | NO FAST] <cursor 选项>; |
<游标名> CURSOR [FAST | NO FAST] <cursor 选项>;
<cursor 选项> := <cursor 选项 1>|<cursor 选项 2>|<cursor 选项 3>|<cursor 选项 4>
<cursor 选项 1>:= <IS|FOR> {<查询表达式>|<连接表>}
<cursor 选项 2>:= <IS|FOR> TABLE <表名>
<cursor 选项 3>:= (<参数声明> {,<参数声明>})IS <查询表达式>
<cursor 选项 4>:= [(<参数声明> {,<参数声明>})] RETURN <DMSQL 数据类型> IS <查询表达式>
<参数声明> ::= <参数名> [IN] <参数类型> [ DEFAULT|:= <缺省值> ]
<DMSQL 数据类型> ::= <普通数据类型>
| <变量名> %TYPE
| <表名> %ROWTYPE
| CURSOR
| REF <游标名>

示例:

DECLARE
	CURSOR c1 IS SELECT TITLE FROM RESOURCES.EMPLOYEE WHERE MANAGERID = 3;
	CURSOR c2 RETURN RESOURCES.EMPLOYEE%ROWTYPE IS SELECT * FROM RESOURCES.EMPLOYEE;
	c3 CURSOR IS TABLE RESOURCES.EMPLOYEE;
……
打开显式游标
OPEN <游标名>;
拨动游标

将游标拨动到结果集的某个位置,获取数据

FETCH [<fetch 选项> [FROM]] <游标名> [ [BULK COLLECT] INTO <主变量名>{,<主变量名>} ] [LIMIT
<rows>];
<fetch 选项>::= NEXT|PRIOR|FIRST|LAST|ABSOLUTE n|RELATIVE n

fetch 选项指定将游标移动到结果集的某个位置:
NEXT:游标下移一行
PRIOR:游标前移一行
FIRST:游标移动到第一行
LAST:游标移动到最后一行
ABSOLUTE n:游标移动到第 n 行
RELATIVE n:游标移动到当前指示行后的第 n 行

示例,使用%NOTFOUND 来判断是否处理完数据并退出循环

DECLARE
	v_name VARCHAR(50);
	v_phone VARCHAR(50);
	c1 CURSOR FOR SELECT NAME,PHONE FROM PERSON.PERSON A,RESOURCES.EMPLOYEE B WHERE
	A.PERSONID=B.PERSONID;
BEGIN
	OPEN c1;
	LOOP
		FETCH c1 INTO v_name,v_phone;
		EXIT WHEN c1%NOTFOUND;
		DM8_SQL 程序设计
		PRINT v_name || v_phone;
	END LOOP;
	CLOSE c1;
END;
/

使用 FETCH…BULK COLLECT INTO 可以将查询结果批量地、一次性地赋给集合变量。
FETCH…BULK COLLECT INTO 和 LIMIT rows 配合使用,可以限制每次获取数据的行数

示例,FETCH…BULK COLLECT INTO 的使用方法

DECLARE
	TYPE V_rd IS RECORD(V_NAME VARCHAR(50),V_PHONE VARCHAR(50));
	TYPE V_type IS TABLE OF V_rd INDEX BY INT;
	v_info V_type;
	c1 CURSOR IS SELECT NAME,PHONE FROM PERSON.PERSON A,RESOURCES.EMPLOYEE B WHERE
	A.PERSONID=B.PERSONID;
BEGIN
	OPEN c1;
	FETCH c1 BULK COLLECT INTO v_info;
	CLOSE c1;
	FOR I IN 1..v_info.COUNT LOOP
		PRINT v_info(I).V_NAME ||v_info(I).V_PHONE;
	END LOOP;
END;
/

BULK COLLECT 可以和 SELECT INTO、FETCH INTO、RETURNING INTO 一起使用,
BULK COLLECT 之后 INTO 的变量必须是集合类型。针对 FETCH…BULK COLLECT INTO 语
句,BULK COLLECT 之后 INTO 的变量不支持索引类型为 VARCHAR 的索引表

关闭游标
CLOSE <游标名>;
显式游标的属性

同样地,每一个显式游标也有%FOUND、%NOTFOUND、%ISOPEN 和%ROWCOUNT 四个属性,但这些属性的意义与隐式游标的有一些区别
%FOUND:如果游标未打开,产生一个异常。否则,在第一次拨动游标之前,其值为 NULL。如果最近一次拨动游标时取到了数据,其值为 TRUE,否则为 FALSE。
%NOTFOUND:如果游标未打开,产生一个异常。否则,在第一次拨动游标之前,其值为 NULL。如果最近一次拨动游标时取到了数据,其值为 FALSE,否则为 TRUE。
%ISOPEN:游标打开时为 TRUE,否则为 FALSE。
%ROWCOUNT:如果游标未打开,产生一个异常。如游标已打开,在第一次拨动游标之前其值为 0,否则为最近一次拨动后已经取到的元组数。

示例,显式游标属性的使用方法。对于基表 EMPSALARY,输出表中的前 5 行数据。如果表中的数据不足 5 行,则输出表中的全部数据:

DECLARE
	CURSOR c1 FOR SELECT * FROM OTHER.EMPSALARY;
	my_ename CHAR(10);
	my_empno NUMERIC(4);
	my_sal NUMERIC(7,2);
BEGIN
	OPEN c1;
	LOOP
		FETCH c1 INTO my_ename, my_empno, my_sal;
		EXIT WHEN c1%NOTFOUND; //当游标取不到数据时跳出循环
		PRINT my_ename || ' ' || my_empno || ' ' || my_sal;
		EXIT WHEN c1%ROWCOUNT=5; //已经输出了 5 行数据,跳出循环
	END LOOP;
	CLOSE c1;
END;
/

动态游标

与静态游标不同,动态游标在声明部分只是先声明一个游标类型的变量,并不指定其关联的查询语句,在执行部分打开游标时才指定查询语句。
动态游标的使用主要在定义和打开时与显式游标不同

定义动态游标

CURSOR <游标名>;

打开动态游标

OPEN [WITH FAST]<游标名><for 表达式>;
<for 表达式>::=<for_item1>|<for_item2>
<for_item1>::= FOR <查询表达式>
<for_item2>::= FOR <表达式> [USING <绑定参数> {,<绑定参数>}]

动态游标在 OPEN 时通过 FOR 子句指定与其关联的查询语句。
WITH FAST:在打开游标时指定 FAST 属性。OPEN 语句中的 WITH FAST 必须在
DM.INI 参数 ENABLE_FAST_REFCURSOR=1 的情况下才能生效,否则只是语法支持并未生
效。

示例,使用动态游标输出员工的姓名、工号和薪水:

DECLARE
	my_ename CHAR(10);
	my_empno NUMERIC(4);
	my_sal NUMERIC(7,2);
	CURSOR c1;
BEGIN
	OPEN C1 FOR SELECT * FROM OTHER.EMPSALARY;
	LOOP
		FETCH c1 INTO my_ename, my_empno, my_sal;
		EXIT WHEN c1%NOTFOUND;
		PRINT '姓名'||my_ename || '工号' || my_empno || ' 薪水' || my_sal;
	END LOOP;
	CLOSE c1;
END;
/

态游标关联的查询语句还可以带有参数,参数以“?”指定,同时在打开游标语句中使
用 USING 子句指定参数,且参数的个数和类型与语句中的“?”必须一一匹配。
示例,使用关联的语句中带有参数的动态游标:

DECLARE
	str VARCHAR;
	CURSOR csr;
BEGIN
	OPEN csr FOR 'SELECT LOGINID FROM RESOURCES.EMPLOYEE WHERE TITLE =? OR TITLE =?'
	USING '销售经理','总经理';
	LOOP
		FETCH csr INTO str;
		EXIT WHEN csr%NOTFOUND;
		PRINT str;
	END LOOP;
	CLOSE csr;
END;
/

拨动和关闭游标

与显式游标相同

参考:
https://eco.dameng.com/

好的,在达梦数据库中编写存储过程时,游标的声明和使用是非常重要的部分。下面我会详细介绍如何在达梦存储过程中声明并使用游标。 ### 游标概述 游标是一个临时的、私有的SQL工作区,它保存了查询结果集,并允许逐行读取这个结果集的数据。通过游标可以对查询到的结果集进行操作,如插入、更新或删除等。 ### 在达梦存储过程中声明游标变量 #### 1. 定义显式游标 要在存储过程中定义显式的游标,你需要先声明一个游标名称及其对应的`SELECT`语句: ```sql DECLARE CURSOR cur_name IS SELECT column_list FROM table_name [WHERE condition]; ``` 例如: ```sql CREATE OR REPLACE PROCEDURE proc_example AS -- 声明游标 CURSOR emp_cur IS SELECT employee_id, first_name, last_name FROM employees WHERE department_id = 50; BEGIN -- 打开游标 OPEN emp_cur; LOOP FETCH emp_cur INTO v_employee_id, v_first_name, v_last_name; -- 把取出的数据放入相应的变量里 EXIT WHEN emp_cur%NOTFOUND; -- 当没有更多记录可提取时退出循环 DBMS_OUTPUT.PUT_LINE('Employee ID: ' || v_employee_id); END LOOP; CLOSE emp_cur; -- 关闭游标释放资源 END proc_example; / ``` 这里我们创建了一个名为 `emp_cur` 的游标用于选择部门编号为50的所有员工信息,并依次将每一行数据存入局部变量当中以便进一步处理。 #### 2. 使用光标变量 (Cursor Variables) 如果你需要从一个PL/SQL块向另一个传递游标,则应该考虑使用光标变量(也称为引用型游标)。这类游标不像普通游标那样预先绑定特定的查询;相反地,它们可以在运行期间动态设置。 首先我们需要导入包 sys.dm_ref_cursor : ```plsql CREATE OR REPLACE PROCEDURE dynamic_query_proc ( p_deptno IN NUMBER, csr OUT SYS_REFCURSOR) IS BEGIN OPEN csr FOR SELECT * FROM employees WHERE department_id = p_deptno ; END dynamic_query_proc; / -- 调用该过程并在客户端程序端获取返回值的方式取决于所使用的工具。 ``` 这种类型的游标对于构建更通用的应用非常有用,因为你可以根据传入的不同条件生成多种查询而不需要改变底层代码结构。 以上就是关于达梦数据库中存储过程内如何声明及运用游标的基础介绍了!
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值