在 PL/SQL 中调用过程时显示的 pluninitialized 集合



我已经看到了其他类似的问题,但我无法理解我的代码中的问题是什么。以下是过程定义

程序.sql

set serveroutput on
create or replace type myarray is varray(1000) of number;
/ 
create or replace procedure Bill(cid in number , bill out number) is
md myarray;
q myarray;
pr myarray;
rs myarray;
begin
bill:=0;
select model,quantity BULK COLLECT into md,q from transactions where customer=cid;
for i in 1..md.COUNT loop
select price BULK COLLECT into pr from computers where model_no=md(i);
END LOOP;
for i in 1..md.COUNT loop
rs(i):=q(i)*pr(i);
end loop;

for i in 1..md.COUNT loop
bill:=bill+rs(i);
end loop;
end;
/
show errors;

这是我调用该过程的文件

呼叫程序.sql

set serveroutput on
declare
bll number(2):=0;
begin
Bill(1,bll);
DBMS_OUTPUT.PUT_LINE('T = '|| bll);
end;
/

如果将数组初始化为空集合:

declare
...
rs myarray := myarray();
begin

然后,您必须增加其容量,无论是在循环中:

for i in 1..md.COUNT loop
rs.extend;
rs(i):=q(i)*pr(i);
end loop;

或一次性(应该更有效(:

rs.extend(md.COUNT);
for i in 1..md.COUNT loop
rs(i):=q(i)*pr(i);
end loop;

在扩展空集合之前,仍必须对其进行初始化。


不过你还有其他问题。您正在执行:

rs(i):=q(i)*pr(i);

rspr集合是完全独立的,因此它们的索引没有任何关系。我认为您每次循环都尝试将记录添加到pr

for i in 1..md.COUNT loop
select price BULK COLLECT into pr from computers where model_no=md(i);
END LOOP;

但您实际上正在做的是将集合的全部内容替换为单个值,而不是追加;在该循环结束时,您将只有md集合中最后一行的价格。对该集合唯一有效的i值是 1,因为只有pr(1)存在(假设model_no是唯一的(;除非客户只有一笔交易不是合适的价格,除了最后一个模型(其中 i != 1(。

您可以在循环中获取相关价格,而无需为此收集:

create or replace procedure Bill(cid in number , bill out number) is
md myarray;
q myarray;
pr number; -- scalar variable
rs myarray := myarray();
begin
select model, quantity bulk collect into md, q from transactions where customer=cid;
rs.extend(md.COUNT);
for i in 1..md.COUNT loop
select price into pr from computers where model_no=md(i); -- not bulk collect
rs(i):=q(i)*pr; -- pr no longer indexed
end loop;
bill:=0;
for i in 1..md.COUNT loop
bill:=bill+rs(i);
end loop;
end;
/

通过联接表并在所有三个集合中执行单个批量收集,使价格与其余数据保持一致会更有效:

create or replace procedure Bill(cid in number , bill out number) is
md myarray;
q myarray;
pr myarray;
rs myarray := myarray();
begin
select t.model, t.quantity, c.price
bulk collect into md, q, pr
from transactions t
join computers c on c.model_no = t.model
where t.customer = cid;
rs.extend(md.COUNT);
for i in 1..md.COUNT loop
rs(i):=q(i)*pr(i);
end loop;
bill:=0;
for i in 1..md.COUNT loop
bill:=bill+rs(i);
end loop;
end;
/

但是,您可以通过在一个循环中执行两个计算来进一步简化:

bill:=0;
rs.extend(md.COUNT);
for i in 1..md.COUNT loop
rs(i):=q(i)*pr(i);
bill:=bill+rs(i);
end loop;

从中你可以看到你根本不需要rs,你可以直接计算账单变化:

create or replace procedure Bill(cid in number , bill out number) is
md myarray;
q myarray;
pr myarray;
begin
select t.model, t.quantity, c.price
bulk collect into md, q, pr
from transactions t
join computers c on c.model_no = t.model
where t.customer = cid;
bill:=0;
for i in 1..md.COUNT loop
bill := bill + q(i)*pr(i);
end loop;
end;
/

但是你根本不需要循环或集合:

create or replace procedure Bill(cid in number , bill out number) is
begin
select sum(t.quantity * c.price)
into bill
from transactions t
join computers c on c.model_no = t.model
where t.customer = cid;
end;
/

显然,您可以仅将该查询作为纯SQL运行,而无需涉及PL/SQL或过程。

取决于您的作业告诉您使用什么...

最新更新