我相信很多的同行应该会有这样的念头:编制一个过程(或者函数),过程中存在一个条件in,对于in的取值希望通过过程的参数来解决,从而达到动态查询的目的。
典型的,过程可以这样编写:
create or replace function sp_testamount(p_name in varchar2) return int
is
i int;
vsql varchar2(4000);
begin
execute immediate 'select count(*) into i from testint where name in (:p_name)' ;
return i;
end;
假设testint.name类型是varchar2,并且假设其中存在数据(共2条记录),分别为:'a'和'b'。
这个时候,也许你希望这样查询:
select sp_testamount('a,b') from dual;结果是0.
或者select sp_testamount('''a'',''b''') from dual,结果依然是0.
看来完全不是想像中那样的语句select count(*) from testint where nane in ('a','b'),这是因为sql引擎中关于char或者varchar2绑定变量的特殊性所导致的。
对于字符类型的绑定变量,oracle总是把其当作一个值来看待,无论传入什么样的值,总是当作一个值来处理,所以无论传入'a,b',或者'''aa'',''b''',sql引擎都会做出类似的解释: in ('a,b'),in ('''a'',''b''')。
因为oracle的sql引擎实在无法辨别你到底是需要传入一个单独的字符串还是用逗号分开的字符串组,只能通通按照一个字符串来处理.
如果希望达到预期的目的,基本有两种方法可以实现:
一、使用到动态sql语句.
vsql:='select count(*) from testint where id in ('||p_name||')';
execute immediate vsql into i ;
在这种情况下,sql引擎对于传入的没有绑定变量的sql语句就会按照我们预想的那样解释SQL,把IN中的内容合理的分解查询。上面这种方法的一个坏处是,传递参数的时候比较麻烦(举例优先,其它的读者自行考虑)。
必须申明的是:目前就字符串类型是这样的,而数值类型则不会受到这样的限制。
概因为oracle的sql引擎还不会把逗号之类的符号认做数值的一部分,因为数值oracle的数值输入还是不允许出现逗号的(显示的时候则允许)。
二、使用instr函数.
execute immediate 'select count(*) into i from testint where instr(p_name,name ) >0;
在这种情况下,利用instr的特性也可以达到效果。