2012-06-20 69 views
0

我有一个关于Oracle中存储过程的问题。 下面是存储过程和表,因为它代表:执行存储在过程参数中的sql语句

create table STORES 
(
    ID number, 
    NAME varchar2(100), 
    CITY varchar2(100), 
    EXPIRES DATE 
) 

insert into stores values(1, 'Store 1', 'City 1', sysdate); 
insert into stores values(2, 'Store 2', 'City 1', sysdate); 
insert into stores values(3, 'Store 3', 'City 2', sysdate); 

create table CLOSED 
(
    ID number, 
    NAME varchar2(100), 
    CITY varchar2(100) 
) 

create or replace PROCEDURE 
pr_TestProc(subQuery IN VARCHAR2) 
IS 
begin 
    insert into CLOSED (ID, NAME, CITY) 
    select ID, NAME, CITY 
    from STORES 
    where ID in (1, 2, 3); 
end; 

我想什么做的是传过来的参数子查询替换“在”值。 所以,如果我喜欢运行的程序:

execute pr_TestProc('select ID from STORES where EXPIRES <= sysdate'); 

传递的查询应执行的过程中正在运行的子查询。 喜欢的东西:

insert into CLOSED (ID, NAME, CITY) select ID, NAME, CITY 
from STORES 
where ID in (execute(subQuery)); 

显然,这是不行的,但是这将是实现这一目标的最佳途径,或者是它甚至可能吗?

感谢, 布赖恩

回答

1

您可以使用动态SQL

create or replace PROCEDURE pr_TestProc(subQuery IN VARCHAR2) 
IS 
    l_sql_stmt varchar2(1000); 
begin 
    l_sql_stmt := 'insert into CLOSED (ID, NAME, CITY) ' || 
       ' select ID, NAME, CITY ' || 
       ' from STORES ' || 
       ' where id in (' || subquery || ')'; 
    dbms_output.put_line(l_sql_stmt); 
    EXECUTE IMMEDIATE l_sql_stmt; 
end; 

SQL> execute pr_TestProc('select ID from STORES where EXPIRES <= sysdate'); 

PL/SQL procedure successfully completed. 

SQL> column name format a20 
SQL> column city format a20 
SQL> select * from closed; 

     ID NAME     CITY 
---------- -------------------- -------------------- 
     1 Store 1    City 1 
     2 Store 2    City 1 
     3 Store 3    City 2 

如果你是在一个系统,是相对空闲很少调用这个程序,这将可能工作得很好。但是,如果您经常使用不同的子查询来调用它,那么您将生成大量不可共享的SQL语句。这将迫使Oracle进行大量的硬解析。它还会将你的共享池泛滥到不可共享的SQL语句中,这可能会迫使你想要缓存的计划,当这些SQL语句再次被执行时强制执行更多的硬解析。如果你做得足够快,你很可能会得到错误(或导致其他进程出错),Oracle无法为共享池中的特定查询分配足够的内存。另外,动态SQL更难编写,更难调试,容易受到SQL注入攻击等,所以通常会导致系统难以处理。

更好的解决方案将是一个集合中传递,而不是一个子查询将是一个集合中传递

SQL> create type id_coll 
    2  as table of number; 
    3/

Type created. 


SQL> ed 
Wrote file afiedt.buf 

    1 create or replace PROCEDURE pr_TestProc(p_ids IN id_coll) 
    2 is 
    3 begin 
    4  insert into CLOSED (ID, NAME, CITY) 
    5  select ID, NAME, CITY 
    6  from STORES 
    7  where ID in (select column_value 
    8      from table(p_ids)); 
    9* end; 
SQL>/

Procedure created. 

SQL> ed 
Wrote file afiedt.buf 

    1 declare 
    2 l_ids id_coll; 
    3 begin 
    4 select id 
    5  bulk collect into l_ids 
    6  from stores 
    7  where expires <= sysdate; 
    8 pr_TestProc(l_ids); 
    9* end; 
SQL>/

PL/SQL procedure successfully completed. 

SQL> select * from closed; 

     ID NAME     CITY 
---------- -------------------- -------------------- 
     1 Store 1    City 1 
     2 Store 2    City 1 
     3 Store 3    City 2 
0

也许你不需要查询传递到存储过程。只需将查询作为参数调用存储过程即可。

create or replace PROCEDURE 
pr_TestProc(listOfIds_IN IN integer) 
IS 
begin 
ids integer := listOfIds_IN; 
insert into CLOSED (ID, NAME, CITY) 
select ID, NAME, CITY from STORES where ID in (ids); 
end; 

调用存储过程是这样的:

pr_TestProc(SELECT id FROM Table WHERE condition) 
相关问题