Оператор вставки и процедура после FORALL

Как я могу иметь один оператор вставки и процедуру вызова после FORALL в plsql?

У меня есть следующее в процедуре

FORALL indx IN p_product.FIRST .. p_product.LAST
        INSERT INTO   my_table
              VALUES   (p_product(indx),p_product_desc(indx),p_msg);

После вставки я хотел бы вызвать другую процедуру, которая вставляет значения в другую таблицу.

remove_dup_products(p_product(indx));

Когда я попытался вызвать вышеуказанную процедуру после оператора вставки, я получаю сообщение об ошибке

INDX must be declared

person Jacob    schedule 08.09.2013    source источник


Ответы (1)


Оператор FORALL — это именно то, что нужно; заявление; вы можете сделать только одну вещь в нем. Вам нужно снова пройтись по вашему типу.

forall indx in p_product.first .. p_product.last
   insert into my_table
   values (p_product(indx), p_product_desc(indx), p_msg);

for indx in p_product.first .. p_product.last loop
   remove_dup_products(p_product(indx));
end loop;

Ничего не стоит то, что вы не выполняете два оператора DML; вы делаете один и вызываете процедуру. Поэтому вы не можете использовать FORALL дважды, вы должны использовать обычный цикл for.

Если вы только выполняете DML во второй процедуре, вы можете передать всю коллекцию, а затем использовать FORALL. Вам нужно будет объявить глобальную переменную:

create or replace package something is

   type t__product is table of product.product%type;
   t_product t__product;

   ...

и тогда вы могли бы повторно использовать это везде

create or replace package body something is

procedure current_proc is

begin

   forall indx in p_product.first .. p_product.last
      insert into my_table
      values (p_product(indx), p_product_desc(indx), p_msg);

   remove_dup_products(p_product);

end current_proc;

-------------------------------------------------------------

procedure remove_dup_products (p_product in t_product) is

begin

    forall in p_product.first .. p_product.last
       delete ...
person Ben    schedule 08.09.2013
comment
Бен, делая это, вызывает ли это переключение plsql на sql? - person Jacob; 08.09.2013
comment
Это зависит от того, что вы делаете в своей процедуре @Polppan; если вы можете переместить материал, который происходит в эту процедуру, в оператор INSERT в том, что вы выполняете, тогда это было бы лучше. - person Ben; 08.09.2013
comment
Бен в процедуре remove_dup_products я удаляю product_id из трех таблиц. Так что это не операторы вставки в процедуру. - person Jacob; 08.09.2013
comment
Пока это DML, это одно и то же @Polppan. Однако я обновил свой ответ другим вариантом. - person Ben; 08.09.2013
comment
@Polppan Переключение контекста будет происходить независимо от того, что вы используете, оператор FORALL или обычный оператор FOR LOOP, вопрос в том, как часто? В случае оператора FORALL, поскольку он отправляет DML операторов в механизм SQL пакетами, это произойдет один раз, тогда как оператор FOR LOOP, поскольку он отправляет оператор DML в механизм SQL по одному, вызовет переключение контекста с каждой итерацией. - person Nick Krasnov; 08.09.2013
comment
@Ben Моя вторая хранимая процедура не является частью пакета. Поэтому я хотел бы создать ROWTYPE, чтобы я мог ссылаться более чем на один столбец из таблицы my_table. Я попытался создать тип как CREATE OR REPLACE TYPE t_product IS TABLE OF my_table%ROWTYPE. Однако я получаю ошибки компиляции. Каков наилучший подход, если я хочу сослаться более чем на один столбец во второй процедуре, чтобы я мог иметь эти столбцы в состоянии удаления, где. Спасибо - person Jacob; 09.09.2013
comment
Однако вам нужно будет явно создать столбцы в вашем типе; @Polppan, вот почему ты получаешь сообщение об ошибке. Я не думаю, что вы можете массово собирать в ряд в 10 г. Чтобы сослаться более чем на один столбец, вы можете передать несколько коллекций; или если ваша процедура состоит только из 3 удалений, вы можете просто повторно реализовать эти удаления в своем текущем пакете и оставлять заметки повсюду. - person Ben; 09.09.2013