PL SQL 过程不引发异常 no_data_found

Posted

技术标签:

【中文标题】PL SQL 过程不引发异常 no_data_found【英文标题】:PL SQL procedure not raising exception no_data_found 【发布时间】:2020-05-13 11:12:06 【问题描述】:

我有两个表 customersorders 如下: 客户:

+----+------+------------+
| ID | Name | Contact_no |
+----+------+------------+
|  1 | Matt | 9435112340 |
|  2 | John | 6654342312 |
|  3 | Jill | 6654342312 |
+----+------+------------+

订单:

+----------+------------+----------+------+
| Order_id | Order_date | Quantity | C_id |
+----------+------------+----------+------+
|     1011 | 09-jan-18  |       30 |    1 |
|     1012 | 09-feb-18  |      300 |    1 |
|     1013 | 09-feb-18  |      200 |    3 |
|     1111 | 09-feb-18  |      100 |    1 |
|     1016 | 09-feb-18  |       20 |    2 |
+----------+------------+----------+------+

我正在编写一个PL/SQL 程序,其中列出了订单数量大于 200 的人的idnamecontact_no。我能够实现这一点。但如果不存在记录,那么我想打印一条消息“未找到记录”。我知道如果没有记录,那么oracle 会抛出no_data_found 异常。因此,我已经根据它编写了我的程序。但是,虽然没有记录,oracle 没有抛出异常,我的 Exception 块没有执行,也没有打印输出。任何人都可以请帮助出了什么问题,我怎样才能达到所需的结果?以下是我的程序。

DECLARE
    CURSOR cust_cur IS
    SELECT * FROM customers WHERE customers.id IN (SELECT c_id FROM orders WHERE orders.quantity>300 group by c_id);
BEGIN
    FOR cust IN cust_cur LOOP
        dbms_output.put_line('Customer_id Customer_Name Customer_Phone');
        dbms_output.put_line(cust.id||' '||cust.name||' '||cust.contact_no);
    END LOOP;
EXCEPTION
    WHEN no_data_found THEN
        dbms_output.put_line('No data found');
    WHEN OTHERS THEN
    dbms_output.put_line('Error Due To -->'|| SQLCODE||SQLERRM);
END;

我已将SQL语句中数量的条件从200改为300,因为它不会返回任何行。

【问题讨论】:

【参考方案1】:

no_data_dound 仅由 select..into..from 子句引发 这个“FOR cust IN cust_cur LOOP”是一个循环,而不是一个 select 语句。这样的循环在 oracle 内部被视为批量收集语句,默认限制为 100。

【讨论】:

那么,我怎样才能达到我想要的结果呢?我需要在procedure 中进行哪些更改? 使用 cust_cur%rowcount。如果这为零,则引发异常。 我刚刚尝试了%rowcount,但仍然无法正常工作 您能否在您的声明中分享对 oracle 文档的引用 - “像这样的oops 在内部被oracle 视为批量收集语句,默认限制为100”。我不认为这是一个正确的说法。 @VN'sCorner :我不记得我是从哪里获得这些知识的。在 Oracle 数据库上工作太久了。不过,我发现这个页面讲述了 oracle 对游标循环的隐式限制:- dba-oracle.com/plsql/t_plsql_limit_clause.htm【参考方案2】:

您可以手动控制循环中的数据计数。 如下所示。

declare
   cursor cust_cur
   is
      select *
        from customers
       where customers.id in (  select c_id
                                  from orders
                                 where orders.quantity > 300
                              group by c_id);

   l_count   number := 0;
begin
   for cust in cust_cur
   loop
      DBMS_OUTPUT.put_line ('Customer_id Customer_Name Customer_Phone');
      DBMS_OUTPUT.put_line (
         cust.id || ' ' || cust.name || ' ' || cust.contact_no);
      l_count := 1;
   end loop;

   if l_count = 0
   then
      raise NO_DATA_FOUND;
   end if;
exception
   when NO_DATA_FOUND
   then
      DBMS_OUTPUT.put_line ('No data found');
   when others
   then
      DBMS_OUTPUT.put_line ('Error Due To -->' || SQLCODE || SQLERRM);
end;

【讨论】:

穆斯塔法的想法是对的!我会使用布尔值 l_rows_round 而不是整数。我也不会引发异常,只是 IF NOT l_rows_found THEN(打印所需信息)。但底线是您想利用游标 for 循环的便利性(和自动优化),然后您必须做一些额外的工作来检测游标在被 PL/SQL 隐式关闭后的行为运行时引擎。 谢谢史蒂文。布尔值听起来更好。我使用“raise”来展示我们如何进入“exception”的原因。你能更简单地解释一下以“bottom line”开头的部分吗?再次感谢您。 当您使用游标进行循环时,Oracle 会为您完成很多工作(隐式声明记录、打开、获取、关闭)。 Plus 会自动优化以在每次提取时返回 100 行。但这也意味着在游标关闭后,对于循环内部发生的事情,您没有任何信息(通过 % cursor 属性)。这有帮助吗? 是的,很清楚。谢谢你的详细解释。

以上是关于PL SQL 过程不引发异常 no_data_found的主要内容,如果未能解决你的问题,请参考以下文章

我的 PL/SQL 过程异常似乎不起作用

PL/SQL 异常不会引发

PL/SQL 异常以啥顺序引发?

PL/SQL 异常和错误处理

为啥在匿名 PL/SQL 块中没有立即引发异常?

引发异常后 PL/SQL 继续