2012-06-20 63 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) 
相關問題