在pl / sql

时间:2018-06-25 21:58:31

标签: sql plsql oracle11g toad

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

Proc.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;

这是我用于调用该过程的文件

CallProc.sql

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

1 个答案:

答案 0 :(得分:1)

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

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

然后,您必须increase its capacity,因为要遍历循环:

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或过程。

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