在使用oracle数据库的查询中,我们都会碰到多字段的查询条件,有like的模糊匹配,有in的过滤,有instr的筛选。现在有两个字符串valA(a,b,c,d)、字符串valB(2,3,b)现在需要匹配B字符串中有没有数据在A中出现,如果有就标识条件成立。如果有上面这么一个情况以上的方式就难以处理了,我们一贯的做法市采用多个OR来拼接查询条件。在使用拼接查询条件过程中往往需要在编程代码或者在数据库服务器上拼接SQL,这样往往让代码的可读性变得很差。那我们今天就说说如何实现。
在编程的路上,我们都会遇到oracle的各种存储过程,视图,方法,触发器……这些所有的oracle提供的对象,我们较常用的是存储过程和视图。
在oracle中存储和函数都能支持输入和输出,为什么我们工作中实际用到的更多的是存储过程而不是函数呢?因为我们往往要返回大量的查询数据,但是函数只能支持一个参数的放回,而且在编写函数的时候使用代码掉用也不容易理解。那什么情况下我们需要使用函数呢?
我的理解如下,当你只有一个返回值(而且非游标数据类型)或者需要做为select语句的表达式进行执行的时候就可以考虑采用函数。第一种情况很好理解,第二种情况的意思就是当你要写一个辅助的逻辑(非业务逻辑)的计算,这个辅助可能在其他很多地方都可以重复利用更业务无关的时候就可以考虑使用自定义函数,我们现在要做的是instr的增强,就是辅助计算,所以采用了自定义方法来实现。
在使用instr的时候我们其实是使用了类似indexOf的操作,如果匹配查找字符串的位置(返回值)大于0,我们就认为条件成立,也就是instr(valA,valB)>0。这样做的弊端就是如果需要查找的valB不是在valA中全匹配,那么就没法满足了。
我们现在将instr增强的思路就是,在输入参数valA中定义查找的范围(并采用逗号分隔),在待匹配参数valB中定义所有需要查找的数据(用逗号分隔)。我们在匹配的时候先把valB用逗号切分,然后将每个切分的数据在valA中去查找,如果有我们就任务条件成立。这就是instr增强的思路。instr增强可以处理如下场景:valA(a,b,c,d)、valB(1,2,3,d)。FUN_INSTR_CONTAINS(valA,valB)>0条件成立。
FUN_INSTR_CONTAINS完整代码如下:
CREATE OR REPLACE FUNCTION FUN_INSTR_CONTAINS(valA IN VARCHAR2,
valB IN VARCHAR2)
RETURN NUMBER IS
FUNCTIONRESULT NUMBER;
strTmp VARCHAR2(4000);
l_str VARCHAR2(500);
ind NUMBER;
BEGIN
strTmp := valB;
FUNCTIONRESULT:=0;
ind:=instr(strTmp,',');
WHILE ind>0 LOOP
l_str:=substr(strTmp,0,ind-1);--截取第一个逗号分割数据
strTmp := substr(strTmp,ind+1);--剩余待处理
ind:=instr(strTmp,',');--重新赋值
SELECT instr(valA,l_str) INTO FUNCTIONRESULT FROM dual;
dbms_output.put_line(l_str);
dbms_output.put_line(strTmp);
EXIT WHEN FUNCTIONRESULT>0 OR ind=0;
END LOOP;
RETURN(FUNCTIONRESULT);
END FUN_INSTR_CONTAINS;
select FUN_INSTR_CONTAINS(valA,valB)from dual;
通过以上处理,我们就可以不用拼接SQL的字符串来处理这种特殊的情况,有些人可能会有疑问,为什么会有这种场景。举个例子:在一个字段中通过group by可能会产生合并结果集(a,b),在提供系统查询的时候,该字段可能属性有多种(a,b,c,d)而且系统提供复选框,这个意思就是系统提供的该字段筛选可以出现(a,b,c,d),后台数据合并之后可能出现的是两种或两种以上的属性(c,d),这时候就需要使用增强instr来处理,而且不用拼接SQL。效率也不会太差,因为改函数处理的是当前行数据的值。