2013-02-15 72 views
1

目前,我有我的PL/SQL代碼下面的語句級聯查詢:PL/SQL重寫用「IN」子句

-- vList looks like '1,2,3,4'  
vStatement := 'SELECT NAME FROM T_USER WHERE ID IN (' || vList || ') '; 
Execute Immediate vStatement BULK COLLECT INTO tNames; 

我認爲,串聯查詢,如果不好的做法,所以我想使這個查詢不用蜇傷。有什麼方法來重寫這個?

P.S.也許這裏的人可以指出爲什麼連接查詢不好,因爲我沒有足夠的理由證明這種風格是不好的。

+0

字符串的鏈接通常是「慢」,但除非你是連接字符串十萬,我看到你的代碼 – 2013-02-15 14:43:11

+0

沒有問題@據我所知,這是pl/sql代碼中的常見做法嗎?因爲我有非常大的查詢產生連接與表名稱,條件等替代... – 2013-02-15 14:58:14

+1

Concatanation傾向於SQL注入攻擊。 – 2013-02-15 15:13:39

回答

2

我的猜測是你之前已經採取了一些步驟將vList id變成分隔字符串(你不會說vList是如何填充的)。爲什麼不保留一個查詢?

begin 
... 
select name 
bulk collect into tNames 
from t_user 
where id in (select id from some_table where ...); 
... 

上下文時多次運行可能是痛苦的切換,但對我來說最糟糕的是,你是盲目地接受參數輸入是數字的列表,當它可以是任何東西真的。它可能(無辜地)是'1,2,X',你會得到一個運行時錯誤「無效號碼」。或者更糟的是,它可能是SQL注入攻擊。一般來說它的不好的做法(動態SQL確實有它的位置),但絕對不是你如何使用它。

嘗試這樣:

create or replace type t_num_tab as table of number; 

create or replace procedure test_proc(i_list in t_num_tab) as 
    type t_name_tab is table of varchar2(100); 
    l_names t_name_tab; 
begin 
    -- get names 
    select name 
    bulk collect into l_names 
    from user_table 
    where id in (select * from table(i_list)); 

    -- do something with l_names 
    dbms_output.put_line('Name count: ' || l_names.count); 

end; 

,如果你需要的東西比數字的列表比較複雜,您可以創建一個對象類型。

+0

實際上它作爲參數傳遞給外部應用程序的存儲過程。 ;( – 2013-02-15 14:56:30

+0

哇,有些方法可以傳遞一組數據,這不是,你甚至可以驗證你的列表是否包含正確/預期的元素?如果我通過'1,2,A'給你,你動態創建一個查詢,當ID是一個數字,你會得到一個運行時錯誤「無效數字」。對不起,我不會咆哮;-) – tbone 2013-02-15 15:15:00

+0

是的,如果數據將無效 - 存儲過程將返回一個錯誤。其實我很樂意把它改寫成通過收藏,但我不知道'如何'。 – 2013-02-15 15:47:25