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 【问题描述】:我有两个表 customers
和 orders
如下:
客户:
+----+------+------------+
| 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 的人的id
、name
和contact_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的主要内容,如果未能解决你的问题,请参考以下文章