ITPUB论坛-中国最专业的IT技术社区

 找回密码
 注册
查看: 1493|回复: 4

[每日一题] PL/SQL Challenge 每日一题:2017-3-14 NO_DATA_FOUND异常

[复制链接]
论坛徽章:
452
秀才
日期:2015-08-18 09:49:27举人
日期:2015-09-09 10:34:21秀才
日期:2015-09-09 10:33:01秀才
日期:2015-09-09 10:33:01状元
日期:2015-09-09 10:34:21榜眼
日期:2015-09-09 10:34:21秀才
日期:2015-09-09 10:33:01秀才
日期:2015-09-09 10:33:01秀才
日期:2015-09-09 10:33:01秀才
日期:2015-09-09 10:33:01
发表于 2017-3-17 03:51 | 显示全部楼层 |阅读模式
(原发表于 2011-6-23)
最先答对且答案未经编辑的puber将获得纪念章一枚(答案不可编辑但可发新贴补充或纠正),其他会员如果提供有价值的分析、讨论也可获得纪念章一枚。

每两周的优胜者可获得itpub奖励的技术图书一本。

以往旧题索引:
http://www.itpub.net/forum.php?m ... eid&typeid=1808

原始出处:
http://www.plsqlchallenge.com/

作者:Steven Feuerstein

运行环境:SQLPLUS, SERVEROUTPUT已打开
注:本题给出答案时候要求给予简要说明才能得到奖品

我创建了如下的表和数据:

CREATE TABLE plch_employees
(
   employee_id   INTEGER
, last_name     VARCHAR2 (100)
, salary        NUMBER
)
/

BEGIN
   INSERT INTO plch_employees
        VALUES (100, 'Jobs', 1000000);

   INSERT INTO plch_employees
        VALUES (200, 'Ellison', 1000000);

   INSERT INTO plch_employees
        VALUES (300, 'Gates', 1000000);

   COMMIT;
END;
/

我还创建了一个名为"plch_employees.txt"的文件,它位于一个文件夹,和数据库中名为"PLCH_TEMP"的DIRECTORY关联(换言之,你可以假定在本题中,这个DIRECTORY已经被定义,我的会话可以从这个DIRECTORY读取)。这个文件包含一行文本:

Ellison

然后我创建了如下的过程:

CREATE OR REPLACE PROCEDURE plch_busy_procedure (
   employee_id_in IN plch_employees.employee_id%TYPE)
IS
   l_employee        plch_employees%ROWTYPE;
   l_line            VARCHAR2 (1023);
   l_file            UTL_FILE.file_type;
   l_list_of_names   DBMS_SQL.varchar2s;
BEGIN
   BEGIN
      SELECT *
        INTO l_employee
        FROM plch_employees e
       WHERE e.employee_id = employee_id_in;

      DBMS_OUTPUT.put_line ('Last Name = ' || l_employee.last_name);
   EXCEPTION
      WHEN OTHERS
      THEN
         DBMS_OUTPUT.put_line (SQLERRM);
   END;

   BEGIN
      l_file := UTL_FILE.fopen ('PLCH_TEMP', 'plch_employees.txt', 'R');
      UTL_FILE.get_line (l_file, l_line);
      UTL_FILE.get_line (l_file, l_line);
      DBMS_OUTPUT.put_line (l_line);
      UTL_FILE.fclose (l_file);
   EXCEPTION
      WHEN OTHERS
      THEN
         DBMS_OUTPUT.put_line (SQLERRM);
         IF UTL_FILE.is_open (l_file)
         THEN
            UTL_FILE.fclose (l_file);
         END IF;
   END;

   BEGIN
        SELECT last_name
          BULK COLLECT INTO l_list_of_names
          FROM plch_employees
      ORDER BY last_name;

      IF l_list_of_names (100) = 'Jobs'
      THEN
         DBMS_OUTPUT.put_line ('A hard worker!');
      END IF;
   EXCEPTION
      WHEN OTHERS
      THEN
         DBMS_OUTPUT.put_line (SQLERRM);
   END;
END plch_busy_procedure;
/

哪些选项显示了我执行如下代码块之后屏幕上的输出?

BEGIN
   plch_busy_procedure (400);
END;
/


(A)
Last name =
Ellison
A hard worker!

(B)
ORA-01403: no data found
ORA-01403: no data found
ORA-01403: no data found



(C)
ORA-01403: no data found
Ellison
A hard worker!

(D)
ORA-01403: no data found
ORA-01403: no data found
A hard worker!

(E)
ORA-01403: no data found
Ellison
ORA-01403: no data found
认证徽章
论坛徽章:
5
弗兰奇
日期:2016-10-24 16:19:30奥运会纪念徽章:体操
日期:2016-08-29 16:30:33蒙奇·D·路飞
日期:2017-03-15 08:47:45娜美
日期:2017-03-15 11:32:24ITPUB15周年纪念
日期:2017-03-20 14:47:54
发表于 2017-3-17 11:49 | 显示全部楼层
答案 B

e.employee_id = employee_id_in  输入的变量400,表中找不到employee_id=400的行

l_list_of_names (100) = 'Jobs'  该数组中只有三个元素,100当然是找不到数据,l_list_of_names (3) = 'Jobs' 可以输出 A hard worker!

UTL_FILE.get_line (l_file, l_line);
UTL_FILE.get_line (l_file, l_line);
DBMS_OUTPUT.put_line (l_line);

这个我看不懂,是第一个UTL_FILE.get_line (l_file, l_line); 读取了之后,缓存就被清空了么?所以第二个读不到?

使用道具 举报

回复
论坛徽章:
0
发表于 2017-3-17 13:23 | 显示全部楼层
答案:D
表中显然不存在Employee_id=400的员工。
第二次UTL_FILE.get_line (l_file, l_line)时会读取不到数据,会报NO_DATA_FOUND的错。
第三个存在下标为100的员工,所以会输出A hard worker!。

个人愚见

使用道具 举报

回复
论坛徽章:
0
发表于 2017-3-17 18:47 来自手机 | 显示全部楼层
试答一下:

使用道具 举报

回复
论坛徽章:
452
秀才
日期:2015-08-18 09:49:27举人
日期:2015-09-09 10:34:21秀才
日期:2015-09-09 10:33:01秀才
日期:2015-09-09 10:33:01状元
日期:2015-09-09 10:34:21榜眼
日期:2015-09-09 10:34:21秀才
日期:2015-09-09 10:33:01秀才
日期:2015-09-09 10:33:01秀才
日期:2015-09-09 10:33:01秀才
日期:2015-09-09 10:33:01
 楼主| 发表于 2017-3-18 03:09 | 显示全部楼层
答案B, 2楼得奖。

NO_DATA_FOUND 可能是PL/SQL中最著名的,最常见的异常。

这个异常在STANDARD包中定义,这是oracle的两个系统包之一。有趣的是,Oracle用了EXCEPTION_INIT pragma来把这个异常和错误代码+100 关联,这是除了1 之外,Oracle使用的唯一正数错误代码,而1被用于用户定义异常。这个错误代码是ANSI标准所指定的。

当这个异常被抛出,对SQLCODE的调用返回100,返回的错误信息则为:

ORA-01403: no data found

这个异常在一系列的情形下被抛出,这包括:

SELECT-INTO找不到数据;
UTL_FILE.GET_LINE 读取到文件末尾;
从一个集合中的未定义索引未知读取一个元素;
用DBMS_LOB.READ读取超过了LOB的末尾;


在这个题目中,ORACLE会三次抛出NO_DATA_FOUND,每次过程的嵌套块都会捕获异常并且显示和这个异常关联的错误信息,即:

ORA-01403: no data found

第一个NO_DATA_FOUND被抛出的原因是没有ID = 400的员工(这是传给过程的参数值)

第二个NO_DATA_FOUND被抛出的原因是因为文件中只有一行文本,但是过程执行了两次UTL_FILE.GET_LINE的调用。

第三个NO_DATA_FOUND被抛出的原因是一个BULK COLLECT 查询总是按顺序从索引值1开始对集合进行填充。因此,索引值1,2,3都有定义,但100没有。

如果你的程序包含了抛出NO_DATA_FOUND的代码,而不在上述列出的情形之内,那么就很难琢磨出什么导致了错误。所以你应该用DBMS_UTLIITY.FORMAT_ERROR_BACKTRACE来定位出错的行号,但你也许想要分隔每片可能抛出NO_DATA_FOUND的代码(利用嵌套的子程序或者嵌套块),这样你就能分别处理它们。

使用道具 举报

回复

您需要登录后才可以回帖 登录 | 注册

本版积分规则

TOP技术积分榜 社区积分榜 徽章 电子杂志 团队 统计 虎吧 老博客 知识索引树 读书频道 积分竞拍 文本模式 帮助
  ITPUB首页 | ITPUB论坛 | 数据库技术 | 企业信息化 | 开发技术 | 微软技术 | 软件工程与项目管理 | IBM技术园地 | 行业纵向讨论 | IT招聘 | IT文档 | IT博客
  ChinaUnix | ChinaUnix博客 | ChinaUnix论坛 | SAP ERP系统
CopyRight 1999-2011 itpub.net All Right Reserved. 北京皓辰网域网络信息技术有限公司版权所有 联系我们 网站律师 隐私政策 知识产权声明
京ICP证:060528号 北京市公安局海淀分局网监中心备案编号:1101082001 广播电视节目制作经营许可证:编号(京)字第1149号
  
快速回复 返回顶部 返回列表