如何显示 oracle 嵌套游标循环的错误消息

how to display error message for oracle nested cursor loops

我有一个项目,它创建一个过程并在参数中使用 Date 参数。执行该过程后,它会使用嵌套游标循环在订单日期列中显示订单 ID 和订单详细信息。我还试图针对我的订单表中不可用的日期显示一条错误消息。 创建程序的代码为

   create or replace procedure a05_order_details_by_date(p_order_date in date)
as
v_msg varchar2(400);
v_order_id ppl_order_headers.order_id%type;
v_order_date ppl_order_headers.order_date%type := p_order_date;

cursor cur_orders is
select order_id, order_date 
from ppl_order_headers
where extract(month from order_date) = extract(month from v_order_date) and
      extract(year from order_date) = extract(year from v_order_date) ;

cursor cur_order_details is
select ppl_order_details.plant_id, ppl_order_details.quantity, ppl_order_details.price, sum(ppl_order_details.quantity*ppl_order_details.price) as Extcost
from ppl_order_details
join ppl_order_headers on ppl_order_details.order_id = ppl_order_headers.order_id
where ppl_order_headers.order_id = v_order_id
group by ppl_order_details.plant_id, ppl_order_details.quantity, ppl_order_details.price; 

begin
<< order_loop >>
for rec_orders in cur_orders
loop
case
when (extract(month from v_order_date)) != (extract(month from rec_orders.order_date))
      and 
     (extract(year from v_order_date))!= (extract(year from rec_orders.order_date)) then
pr.pr('There are no orders for the requested month: ' || to_char(v_order_date, 'Month YYYY'));
else
pr.pr('Order ID' || '                   ' || 'Order Date'); 
v_order_id := rec_orders.order_id;
v_msg := rpad(v_order_id, 7) || '                    ' || rec_orders.order_date;
pr.pr(v_msg);
<< order_details >>
for rec_order_details in cur_order_details
loop
pr.pr('                           ' || '    Plant ID' || '    ' || 'Quantity' || '    ' || 'Price' || '    ' || 'ExtCost' );
 v_msg := '                                   ' || rec_order_details.plant_id || '          ' || rec_order_details.quantity ||
          '     ' || rec_order_details.price || '      ' || rec_order_details.Extcost;
pr.pr(v_msg);
end loop;
end case;
end loop;
end;
/

在数据集中给出日期时,结果很好。但是当我尝试 运行 具有未来日期或不在数据集中的日期的过程时,它应该显示一条错误消息。但是,它只显示 "Anonymous Block completed".

您正在遍历订单日期 year/month 与您的参数 year/month 匹配的订单;所以你的循环只包含匹配的数据。但是然后在那个循环中你说:

case
when (extract(month from v_order_date)) != (extract(month from rec_orders.order_date))
      and 
     (extract(year from v_order_date))!= (extract(year from rec_orders.order_date)) then

首先你的意思可能是'or'而不是'and',否则不同年份的同月仍然有效。但更重要的是,案例条件永远不会为真。由于游标的 where 子句,您处于一个循环中,该循环已经规定该记录的月份和年份必须与您的日期参数匹配。

所以这个case语句是多余的。如果游标找到任何数据,那么您将始终进入 'else' 子句。如果没有找到数据,那么您根本不会进入游标循环(正如 Tony Andrews 指出的那样),因此甚至不会评估这种情况。

您可以通过计算循环中找到的记录数或设置布尔变量来生成消息;然后在循环后检查该状态:

...
  -- initial state is that we haven't seen any matching records
  v_record_found boolean := false;
begin
  << order_loop >>
  for rec_orders in cur_orders
  loop
    -- we have seen records matching the argument
    v_record_found := true;

    pr.pr('Order ID' || '                   ' || 'Order Date'); 
    v_order_id := rec_orders.order_id;
    ...
    << order_details >>
    for rec_order_details in cur_order_details
    loop
      pr.pr(...)
      ...
      pr.pr(v_msg);
    end loop;
  end loop;

  -- was the flag changed inside the loop?
  if not v_record_found then
    pr.pr('There are no orders for the requested month: '
     || to_char(v_order_date, 'Month YYYY'));
  end if;
end;

如果没有匹配的记录,您就不会进入循环,并且标志永远不会更改为 true。但是,如果有匹配的记录,它将设置为 true,并且不会显示 'no orders' 消息。