如何显示 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' 消息。
我有一个项目,它创建一个过程并在参数中使用 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' 消息。