ICode9

精准搜索请尝试: 精确搜索
首页 > 数据库> 文章详细

PLSQL入门与精通(第76章:表行数的异常处理NO_DATA_NEEDED)

2021-03-28 21:01:45  阅读:225  来源: 互联网

标签:f1 PLSQL NO 处理 游标 MSG rec DATA 函数


上次介绍了“表·函数”,在使用表·函数时,有些注意事项要注意。

那就是使用“WHERE ROWNUM<=n”想取前几条数据相关的注意事项。

例如,请看以下我们用“WERE ROWNUM<=n”对表·函数进行查询。

SELECT * FROM TABLE (pac1.f1(5)) WHERE ROWNUM <= 2;
COL1 COL2


1 ABC1
2 ABC2

上面的表函数pac1.f1(5)是处理5次循环,每次循环返回一条数据,总共返回五条数据。
也就是说这个函数如果没有查询条件的话,可以返回5行数据。
但是,因为WHERE句有ROWNUM<=2这个条件,所以只需要前两行数据。

在这种情况下,表函数会在最初的两行中中断处理,有时会产生问题。

按顺序确认一下吧:

便于理解,在表·函数中追加了部分输出信息的处理。

CREATE OR REPLACE PACKAGE BODY pac1
IS
//
/表函数f1的定义/
/
/
FUNCTION f1(p1 IN NUMBER) RETURN rec_tab_type PIPELINED
IS
rec rec_type;
BEGIN
FOR I IN 1…p1 LOOP
rec.col1 := I;
rec.col2 := ‘ABC’ || TO_CHAR(I);
PIPE ROW(rec);
END LOOP;
DBMS_OUTPUT.PUT_LINE(‘MSG:返回了所有的行’);–这是本次添加的处理
RETURN ;
END f1;
END PAC1;
/

包主体创建完成。

通过添加PUT_LINE的处理,如果处理不中断的话,在返回到最后一行时,
会输出“MSG:返回了所有的行”的信息,因此可以根据这个信息可以判断处理是否执行到了最后。

试一下效果:

SET SERVEROUTPUT ON

为了返回所有的行,不加查询条件去查询表·函数。p1参数值设为5,循环5次返回5行。

SELECT * FROM TABLE (pac1.f1(5));
COL1 COL2


1 ABC1
2 ABC2
3 ABC3
4 ABC4
5 ABC5

MSG:返回了所有的行

最后有“MSG:返回了所有的行”这样的信息。
从而判断处理到了最后。这个和想的的一样。

接着我们试着加上“WHRE COL1=3”的查询条件在看看:

SELECT * FROM TABLE (pac1.f1(5)) WHERE COL1 = 3;
COL1 COL2


3 ABC3

MSG:返回了所有的行

因为加了查询条件,所以只显示了一行。

但是,在这种情况下也出现了“MSG:返回了所有的行”的信息。
和我们预想的不太一样,但是结果就是这样子。
也就是说,虽然实际上表·函数已经返回了5行,但是根据查询的“WHERE COL1=3”的条件,
只返回了5行中满足条件的1行。

再接着,我们加上查询条件是“WHRE ROWNUM<=2”在看一下效果:

SELECT * FROM TABLE (pac1.f1(5)) WHERE ROWNUM <= 2;

COL1 COL2


1 ABC1
2 ABC2

在这种情况下,最后没有显示“MSG:返回了所有的行”的信息。

也就是说,这个表函数在中途处理就结束了。

解释如下:
表函数在PIPE ROW处理(第13行源代码)中及时一行一行返回数据,
但是如果超过ROW NUM指定的行数,继续进行PIPE ROW处理的话,
则会发生NO DATA NEEDID的例外(NO DATA FOUND例外))。

程序中又没有处理这个例外,也就是说如果在例外处理部中未记述OTHERS处理程序或NO DATA NEEDID例外处理程序,
程序会以未处理例外的形式结束。
在这种情况下,表函数里边如果用UTL_FILE包等打开文件的话,就会以例外处理直接结束程序,
文件也不会关闭,这样的程序是有问题的。

如果是用到游标的话,游标也不会被关闭,反复执行这样的处理,数据库开启游标数就会达到上限
并发生错误。

因此,表·函数里边要进行NO DATA NEEDID例外处理,相关资源(譬如打开的文件,或者游标等)要进行关闭。

刚才的例子中我们追加相应的NO DATA NEEDID例外处理程序。结果如下:

注意:因为这个例子处理中没有打开文件和游标,所以这个例外处理没有太大的意义,
但是,我们只能通过特定的方式,确认一下这个例外是否会发生。

CREATE OR REPLACE PACKAGE BODY pac1
IS
//
/表函数f1的定义/
/
/
FUNCTION f1(p1 IN NUMBER) RETURN rec_tab_type PIPELINED
IS
rec rec_type;
BEGIN
FOR I IN 1…p1 LOOP
rec.col1 := I;
rec.col2 := ‘ABC’ || TO_CHAR(I);
PIPE ROW(rec);
END LOOP;
DBMS_OUTPUT.PUT_LINE(‘MSG:返回了所有行’);
RETURN ;
EXCEPTION-追加
WHEN NO DATA NEEDED THEN–追加
DBMS_OUTPUT.PUT_LINE(‘MSG:处理中途停止了’);–本次添加的处理
RETURN;–添加
END f1;
END PAC1;
/

包主体创建完成。

实际去看看吧。

SELECT * FROM TABLE (pac1.f1(5)) WHERE ROWNUM <= 2;
COL1 COL2


1 ABC1
2 ABC2

MSG:处理中途停止

最后的信息「MSG:处理中途停止」出现了。

上述函数没有打开游标和文件等,所以异常处理没什么意义,
表·函数中如果有打开文件或者游标的话,上述的“MSG:返回了所有行”“MSG:处理中途停止了”
等输出信息的处理部分就需要该成关闭文件或者游标的处理了。

因此,管道表函数在“WEHERE ROWNUM<=n”这样的查询条件下内部会发生“NO DATA NEEDID”例外,
因此在打开文件和游标的情况下,除了通常的关闭处理外,还需要使用NO DATA NEEDID例外处理程序
来实施关联的关闭处理。

那么,作为简单的例子,最后把这次的pac1.f1函数改写成使用明示游标的内容。

CREATE OR REPLACE PACKAGE BODY pac1
IS
/*********************************************************************/
/表·函数f1的定义(按照部门编号对应的返回员工)/
/*********************************************************************/
FUNCTION f1(p1 IN NUMBER) RETURN rec_tab_type PIPELINED
IS
–申明游标:返回指定部门编号的员工
CURSOR c1 is SELECT * FROM EMP WHERE DEPTNO = p1;
emp_rec%rowtype;–游标的行记录变量
rec rec_type;–表函数的行记录变量
BEGIN
OPEN C1;–游标打开
LOOP–重复以下处理
FETCH c1 into emp_rec;–取得1行数据
EXIT WHEN c1%NOTFTOUND;–没有取得的数据时,退出循环
rec.col1 := emp_rec.empno;–设置表·函数行的col 1列的值
rec.col2 := emp_rec.ename;–设置表·函数行的col 2列的值
PIPE ROW(rec);–通过管道返回表·函数行
END LOOP;
CLOSE c1;–循环结束后关闭游标
RETURN; --结束表函数
EXCEPTION
WHEN NO DATA NEEDEDED THEN
CLOSEc1;–关闭游标
RETURN;–结束表函数
END f1;
END PAC1;
/

包主体创建完成。

那么试着实行一下吧。首先是部门号30号员工的查询。

SELECT * FROM TABLE (pac1.f1(30));
COL1 COL2


7499 ALLEN
7521 WARD
7654 MARIN
7698 BLAKE
7844 TURNER
7900 JAMES

选择了6行。

那么接下来,我们加上ROWNUM条件,只查询前两行。

SQL> SELECT * FROM TABLE (pac1.f1(30)) WHERE ROWNUM <= 2;
COL1 COL2


7499 ALLEN
7521 WARD

结果会正确地返回。

在有「WHRE ROWNUM<=n」条件和没有条件的情况下,这个表函数结束的时候,
游标是一直打开的没有关闭。

本次到此为止。

标签:f1,PLSQL,NO,处理,游标,MSG,rec,DATA,函数
来源: https://blog.csdn.net/niusr_1980_01/article/details/115287482

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有