--===============================
-- PL/SQL --> 隐式游标 (SQL%FOUND)
--===============================
在 PL / SQL 中,游标的使用分为两种,一种是显示游标,一种是隐式游标,显示游标的使用需要事先使用 declare 来进行声明,其过程包括
声明游标,打开游标,从游标提取数据,关闭游标。该方式多用于处理 select 语句返回的多行数据的情形。而隐式游标则由则由系统自动定义
,当 DML 被使用时, Oracle 为每一个不属于显示游标的 DML 语句都创建一个隐式游标,其声明、打开、关闭都是系统自动进行。多用于配合 DML
返回单行数据的处理。
有关显示游标的使用,请参考: PL/SQL --> 游 标
一、隐式游标的定义及其属性
定义
隐式游标则由则由系统自动定义,非显示定义游标的 DML 语句即被赋予隐式游标属性。其过程由 oracle 控制,完全自动化。隐式游标
的名称是 SQL ,不能对 SQL 游标显式地执行 OPEN , FETCH , CLOSE 语句。
属性
类似于显示游标,隐式游标同样具有四种属性,只不过隐式游标以 SQL % 开头,而显示游标以 Cursor_name % 开头
通过 SQL % 总是只能访问前一个 DML 操作或单行 SELECT 操作的游标属性,用于判断 DML 执行的状态和结果,进而控制程序的流程
SQL % ISOPEN
游标是否打开。当执行 select into , insert update , delete 时, Oracle 会隐含地打开游标,且在该语句执行完毕或隐含地关闭
游标,因为是隐式游标,故 SQL % ISOPEN 总是 false
SQL % FOUND
判断 SQL 语句是否成功执行。当有作用行时则成功执行为 true ,否则为 false 。
SQL % NOTFOUND
判断 SQL 语句是否成功执行。当有作用行时否其值为 false ,否则其值为 true 。
SQL % ROWCOUNT
在执行任何 DML 语句之前, SQL % ROWCOUNT 的值都是 NULL, 对于 SELECT INTO 语句,如果执行成功, SQL % ROWCOUNT 的值为 , 如果没有
成功, SQL % ROWCOUNT 的值为,同时产生一个异常 NO_DATA_FOUND 。
二、演示
1.SQL % FOUND 的使用
DECLARE
v_empno emp . empno % TYPE :=& no ;
BEGIN
UPDATE emp SET sal = sal + 200 -- 根据给定的 empno ,更新一条记录
WHERE empno = v_empno ;
IF SQL % FOUND THEN -- 使用 SQL 游标属性 SQL%FOUND 作为判断条件
COMMIT ;
DBMS_OUTPUT . PUT_LINE ( 'SQL code is executed successful' );
ELSE
DBMS_OUTPUT . PUT_LINE ( 'The Employee is not exist' );
ROLLBACK ;
END IF ;
END ;
Enter value for no : 7788
old 2 : v_empno emp . empno % TYPE :=& no ;
new 2 : v_empno emp . empno % TYPE := 7788 ;
SQL code is executed successful
PL / SQL procedure successfully completed
2.SQL 游标的综合应用 ( 根据 SQL 游标的不同属性返回不同的结果 )
DECLARE
v_dept emp . deptno % TYPE := & no ;
BEGIN
IF SQL % ROWCOUNT >= 0 THEN -- 判断更新前 SQL%ROWCOUNT 的属性
DBMS_OUTPUT . PUT_LINE ( 'SQL%ROWCOUNT value is ' || SQL % ROWCOUNT ||
'before updated' );
ELSE
DBMS_OUTPUT . PUT_LINE ( 'SQL%ROWCOUNT value is NULL before updated' );
END IF ;
UPDATE emp SET sal = sal + 200 WHERE deptno = v_dept ;
IF SQL % FOUND THEN -- 判断 SQL%FOUND 的属性
DBMS_OUTPUT . PUT_LINE ( 'SQL code is executed successful' );
DBMS_OUTPUT . PUT_LINE ( 'SQL%Found is TRUE' );
ELSE
DBMS_OUTPUT . PUT_LINE ( 'No such department' );
DBMS_OUTPUT . PUT_LINE ( 'SQL%Found is FALSE' );
END IF ;
IF SQL % NOTFOUND THEN -- 判断 SQL%NOTFOUND 的属性
DBMS_OUTPUT . PUT_LINE ( 'SQL%NotFound is TRUE' );
ELSE
DBMS_OUTPUT . PUT_LINE ( 'SQL%NotFound is FALSE' );
END IF ;
IF SQL % ISOPEN THEN -- 判断 SQL%ISOPEN 的属性
DBMS_OUTPUT . PUT_LINE ( 'SQL%ISOPEN is TRUE' );
ELSE
DBMS_OUTPUT . PUT_LINE ( 'SQL%ISOPEN is FALSE' );
END IF ;
DBMS_OUTPUT . PUT_LINE ( 'The rows updated is :' || SQL % ROWCOUNT ||
' rows by SQL Cursor' ); -- 判断 SQL%ROWCOUNT 的属性
END ;
Enter value for no : 10 -- 下面是成功更新后的结果
SQL % ROWCOUNT value is NULL before updated
SQL code is executed successful
SQL % Found is TRUE
SQL % NotFound is FALSE
SQL % ISOPEN is FALSE
The rows updated is : 3 rows by SQL Cursor
Enter value for no : 80 -- 下面是未成功更新后的结果
SQL % ROWCOUNT value is NULL before updated
No such department
SQL % Found is FALSE
SQL % NotFound is TRUE
SQL % ISOPEN is FALSE
The rows updated is : 0 rows by SQL Cursor
3. SELECT INTO 时,隐式游标的使用
SELECT INTO 用于将单行结果集放置到变量之中。
SELECT INTO 处理的结果包括两种种情况
查询结果返回单行, SELECT INTO 被成功执行
查询结果没有返回行, PL / SQL 将抛出 no_data_found 异常
查询结果返回多行, PL / SQL 将抛出 too_many_rows 异常
对于上述两种异常发生时,类似于普通异常处理,程序控制权转移到异常处理部分 ( 如没有异常处理则程序中断 ) 。对于异常被激后发
, SQL 游标的四个属性在此将不可使用,如下面的例子:
DECLARE
v_ename emp . ename % TYPE ;
BEGIN
SELECT ename INTO v_ename FROM emp WHERE empno =& no ;
IF SQL % ROWCOUNT = 0 OR SQL % NOTFOUND THEN
DBMS_OUTPUT . PUT_LINE ( 'The record ' ||& no|| ' is not exist!' );
ELSE
DBMS_OUTPUT . PUT_LINE ( 'The name for record ' ||& no|| ' is ' || v_ename );
END IF ;
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT . PUT_LINE ( 'No data found for ' ||& no );
END ;
Enter value for no : 70
No data found for 70
Enter value for no : 7788
The name for record 7788 is SCOTT
从上面的演示中可以看到,当 select into 没有返回行时, IF SQL % ROWCOUNT = 0 OR SQL % NOTFOUND THEN 语句并没有被执行。
使用下面改进过的代码来执行,即可以将 SQL 游标属性判断放置到 EXCEPTION 部分
DECLARE
v_ename emp . ename % TYPE ;
BEGIN
SELECT ename INTO v_ename FROM emp WHERE empno =& no ;
IF SQL % NOTFOUND THEN
DBMS_OUTPUT . PUT_LINE ( 'The record ' ||& no|| ' is not exist!' );
ELSE
DBMS_OUTPUT . PUT_LINE ( 'The name for record ' ||& no|| ' is ' || v_ename );
END IF ;
EXCEPTION
WHEN NO_DATA_FOUND THEN
IF SQL % NOTFOUND THEN
DBMS_OUTPUT . PUT_LINE ( 'The record ' ||& no|| ' is not exist!' );
DBMS_OUTPUT . PUT_LINE ( 'No data found for ' ||& no );
ELSE
DBMS_OUTPUT . PUT_LINE ( 'The name for record ' ||& no|| ' is ' || v_ename );
END IF ;
END ;
Enter value for no : 80
The record 80 is not exist !
No data found for 80
更多关于隐式游标的探讨,请参考: IMPLICIT CURSOR ATTRIBUTE SQL%NOTFOUND NOT WORKING
三、更多参考
有关 SQL 请参考
SQL 基础--> ROLLUP 与CUBE 运算符实现数据汇总
SQL 基础--> 层次化查询(START BY ... CONNECT BY PRIOR)
有关 PL/SQL 请参考