我已经看到了其他类似的问题,但我无法理解我的代码中的问题是什么。以下是过程定义
程序.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);
但rs
和pr
集合是完全独立的,因此它们的索引没有任何关系。我认为您每次循环都尝试将记录添加到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或过程。
取决于您的作业告诉您使用什么...