Если вы инициализируете массив как пустую коллекцию:
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 илиПроцедура вообще.
Зависит от того, что ваше назначение говорит вам использовать ...