2017-02-08 5 views
2

У меня есть список процедур, которые нужно вызывать в данном порядке для всех строк таблицы. Вместо того, чтобы жестко кодировать вызовы процедур, я хотел бы добавить их все в отдельную таблицу и перебрать строки, содержащие процедуры, вызывающие их. Все процедуры требуют одинаковых входных параметров.Вызов хранимой процедуры PLSQL с использованием строкового представления имени

Возможно ли это?

ответ

5

Скажем, у вас есть эта таблица:

create table procs(procName) as (
    select 'proc1' from dual union all 
    select 'proc2' from dual union all 
    select 'proc3' from dual 
)  

и эти процедуры:

create or replace procedure proc1(p1 in varchar2, p2 in number) is begin dbms_output.put_line('running Proc1(' || p1 || ', ' || p2 || ')'); end; 
create or replace procedure proc2(p1 in varchar2, p2 in number) is begin dbms_output.put_line('running Proc2(' || p1 || ', ' || p2 || ')'); end; 
create or replace procedure proc3(p1 in varchar2, p2 in number) is begin dbms_output.put_line('running Proc3(' || p1 || ', ' || p2 || ')'); end; 

Вы можете попробовать:

declare 
    yourParameter1 varchar2(10) := 'X'; 
    yourParameter2 number  := 10; 
begin 
    for i in (select procName from procs order by procName) loop 
     execute immediate 'begin ' || i.procName || '(:1, :2); end;' using yourParameter1, yourParameter2; 
    end loop; 
end; 

Что вы получите:

running Proc1(X, 10) 
running Proc2(X, 10) 
running Proc3(X, 10) 
+0

Замечательно, огромное спасибо! – bjelleklang

2

Предположим, у вас есть таблица procedures_to_run, где столбец name обрабатывает имена выполняемых процедур и id, который определяет их порядок. Вы можете позвонить:

begin 
for x in (select name from procedures_to_run order by id) loop 
    execute immediate 'call '|| x.name ||'(INPUT_PARAMS)'; 
end loop; 
end; 

, чтобы выполнить все процедуры.

+0

Извините, но что не так с ответом на то, что он получает downvoted? – Kacper

+0

Не использовать переменную связывания –

+0

Автор сказал, что всем процедурам нужны одни и те же параметры, поэтому жесткое кодирование их не повредит. Но да, я согласен, что переменные привязки делают код лучше здесь. Благодарю. – Kacper

1

Это, вероятно, избыточна в этом примере, но для такого рода вещи можно инкапсулировать execute immediate внутри определения типа, так что цикл может просто выполнить что-то вроде r.task.run();

Определить тип «задачи»:

create or replace type task as object 
(command varchar2(100) 
, member procedure run); 
/

create or replace type body task 
as 
    member procedure run 
    is 
    begin 
     execute immediate 'begin ' || self.command || '; end;'; 
    exception 
     when others then 
      raise_application_error(-20000, 'Command failed: ' || self.command, true); 
    end run; 
end; 
/

Теперь ваша таблица может иметь столбец «задачи» вместо простой строки:

create table demo_tasks 
(created_tate date default sysdate not null 
, last_run_date date 
, succeeded_yn varchar2(1) check (succeeded_yn in ('Y','N')) 
, task   task not null); 

Некоторые демо-процедуры:

create or replace procedure p1 as begin dbms_output.put_line('This is ' || $$plsql_unit); end; 
/
create or replace procedure p2 as begin dbms_output.put_line('This is ' || $$plsql_unit); end; 
/
create or replace procedure p3 as begin dbms_output.put_line('This is ' || $$plsql_unit); end; 
/

insert into demo_tasks (task) values (task('p1')); 
insert into demo_tasks (task) values (task('p2')); 
insert into demo_tasks (task) values (task('p3')); 

Перебор сохраненных задач выполнения каждой из них:

begin 
    for r in (
     select * from demo_tasks 
    ) 
    loop 
     -- Add code here to update run date, status etc 
     r.task.run(); 
    end loop; 
end; 
/

This is P1 
This is P2 
This is P3 

Он не может купить вам много в этом примере, но это стоит иметь в виду, как подход.

Смежные вопросы