2012-06-14 93 views
1

這隻適用於我只有一個州代碼作爲參數。如何在'where value in ...'子句中使用參數?

當我在parm_list中有多個state_code時,如何獲取代碼以工作?

要求:

(1)我不想硬編碼在我的光標定義的狀態代碼

(2)我想允許一個以上的國家代碼在我的where子句

例如:我想運行此代碼爲parm_list =('NY','NJ','NC')。 我在parm_list中的單引號與'where state_code in'查詢中的單引號遇到困難。

set serveroutput on; 

DECLARE 
parm_list varchar2(40); 

cursor get_state_codes(in_state_codes varchar2) 
is 
select state_name, state_code from states 
where state_code in (in_state_codes); 

BEGIN 
parm_list := 'NY'; 
for get_record in get_state_codes(parm_list) loop 
    dbms_output.put_line(get_record.state_name || get_record.state_code); 
end loop; 
END; 
+0

你可以看到我的答案(或任何你喜歡的。)在http://stackoverflow.com/a/18100419/947356 我希望這會幫助你。 – Sergey

回答

11

從編碼的角度來看,使用動態SQL是最簡單的方法。然而,動態SQL的問題在於,你必須努力解析查詢的每個不同版本,這不僅可能會導致CPU處理稅,而且有可能會用大量不可共享的SQL語句淹沒共享池,推動你想要緩存的聲明,導致更多的硬解析和共享池碎片錯誤。如果你每天運行一次,這可能不是一個主要問題。如果數百人每天執行數千次,那可能是一個主要問題。

動態SQL方法

SQL> ed 
Wrote file afiedt.buf 

    1 declare 
    2 l_deptnos varchar2(100) := '10,20'; 
    3 l_rc  sys_refcursor; 
    4 l_dept_rec dept%rowtype; 
    5 begin 
    6 open l_rc for 'select * from dept where deptno in (' || l_deptnos || ')'; 
    7 loop 
    8  fetch l_rc into l_dept_rec; 
    9  exit when l_rc%notfound; 
10  dbms_output.put_line(l_dept_rec.dname); 
11 end loop; 
12 close l_rc; 
13* end; 
SQL>/
ACCOUNTING 
RESEARCH 

PL/SQL procedure successfully completed. 

交替的例子,你可以使用一個集合。這具有生成單個可共享遊標的優勢,因此您不必擔心硬解析或泛洪共享池。但它可能需要更多的代碼。爲處理集合最簡單的方法

SQL> ed 
Wrote file afiedt.buf 

    1 declare 
    2 l_deptnos tbl_deptnos := tbl_deptnos(10,20); 
    3 begin 
    4 for i in (select * 
    5    from dept 
    6    where deptno in (select column_value 
    7         from table(l_deptnos))) 
    8 loop 
    9  dbms_output.put_line(i.dname); 
10 end loop; 
11* end; 
SQL>/
ACCOUNTING 
RESEARCH 

PL/SQL procedure successfully completed. 

如果,另一方面,你真的要開始用逗號分隔值的列表中,那麼你將有該字符串解析爲一個集合纔可以使用它。有多種方法來解析分隔string--我個人最喜歡的是在分層查詢使用正則表達式,但你當然可以寫一個程序的方法,以及

SQL> ed 
Wrote file afiedt.buf 

    1 declare 
    2 l_deptnos  tbl_deptnos; 
    3 l_deptno_str varchar2(100) := '10,20'; 
    4 begin 
    5 select regexp_substr(l_deptno_str, '[^,]+', 1, LEVEL) 
    6  bulk collect into l_deptnos 
    7  from dual 
    8 connect by level <= length(replace (l_deptno_str, ',', NULL)); 
    9 for i in (select * 
10    from dept 
11    where deptno in (select column_value 
12         from table(l_deptnos))) 
13 loop 
14  dbms_output.put_line(i.dname); 
15 end loop; 
16* end; 
17/
ACCOUNTING 
RESEARCH 

PL/SQL procedure successfully completed. 
+0

非常感謝那很好的解釋它與我合作 – sam

7

一種選擇是使用INSTR代替的:

SELECT uo.object_name 
     ,uo.object_type 
FROM user_objects uo 
WHERE instr(',TABLE,VIEW,', ',' || uo.object_type || ',') > 0; 

雖然這看起來醜陋,它工作得很好,只要列上沒有索引正在測試將要被使用(因爲這可以防止使用任何指數)的性能不會受到太大。如果被測試的列是主鍵,則絕對不應該使用。

另一種選擇是:

SELECT uo.object_name 
     ,uo.object_type 
FROM user_objects uo 
WHERE uo.object_type IN 
     (SELECT regexp_substr('TABLE,VIEW', '[^,]+', 1, LEVEL) 
     FROM dual 
     CONNECT BY regexp_substr('TABLE,VIEW', '[^,]+', 1, LEVEL) IS NOT NULL); 

在這種情況下,值的列表應連接到單一的VARCHAR變量,用逗號分隔的

+0

這對我的情況非常適用,所以也很容易使用。 – dangel

相關問題