PL / SQL使用'IN'子句重写连接查询

时间:2013-02-15 14:36:23

标签: oracle plsql where-clause dynamic-sql

目前我的pl / sql代码中包含以下语句:

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

我认为连接查询是不好的做法,所以我想在不使用stings的情况下进行此查询。重写这个的方法是什么?

P.S。也许这里的人可以指出为什么查询连接不好,因为我没有足够的理由来证明这种风格是坏的。

2 个答案:

答案 0 :(得分: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;

如果您需要比数字列表更复杂的东西,则可以创建对象类型。

答案 1 :(得分:1)

这不仅仅是连接缓慢。这是plsql中的动态查询真的很慢。这里有关于如何以及为什么要这样做的好文章:

Ask Tom: How can I do a variable "in list"