正如我在评论中所说,原则上使用case
你所展示的应该有效(我所说的“工作”是指产生相同的结果;这并不一定意味着它会更好,并且可能会对性能和维护产生影响等)。为了演示,我将创建一些虚拟数据:
create table t42 (flag varchar2(1), value varchar2(10), cond number);
insert into t42 values ('Y', 'One', 1);
insert into t42 values ('Y', 'Two', 2);
insert into t42 values ('Y', 'Three', 3);
...和一个包中的两个程序:
create package p42 as
procedure proc1(parm number);
procedure proc2(parm number);
end p42;
/
create package body p42 as
procedure proc1(parm number) is
basic_query varchar2(1000);
final_query varchar2(1500);
where_clause varchar2(500) default null;
result t42.value%type;
begin
basic_query := 'select value from t42 where flag = ''Y'' ';
if parm = 2013 then
where_clause := 'and cond = 1 ';
elsif parm = 2012 then
where_clause := 'and cond = 2 ';
else
where_clause := 'and cond = 3 ';
end if;
final_query := basic_query || where_clause;
execute immediate final_query into result;
dbms_output.put_line(result);
end proc1;
procedure proc2(parm number) is
result t42.value%type;
begin
select value into result from t42 where flag = 'Y'
and case
when parm = 2013 and cond = 1 then 'valid'
when parm = 2012 and cond = 2 then 'valid'
when not (parm = 2013 or parm = 2012) and cond = 3 then 'valid'
else 'invalid' end = 'valid';
dbms_output.put_line(result);
end proc2;
end p42;
/
我proc1
相信,本质上就是在做你原来的动态查询所做的事情。proc2
正在使用您的case
构造。显然条件是完全组成的,并且可变where
子句在这种形式下会很愚蠢,但这只是关于case
.
使用 parm (2013, 2012, 2011) 的各种值运行会在两个过程中返回相同的行,因此它们在这个意义上是等效的
exec p42.proc1(2013);
One
exec p42.proc2(2013);
One
我怀疑你的最终条件是错误的。当然我猜,因为您发布的伪代码到目前为止已从您的实际查询中删除,我们无法看到您可能做错了什么。但是如果你做了这样的事情:
and case
when parm = 2013 and cond = 1 then 'valid'
when parm = 2012 and cond = 2 then 'valid'
when cond = 3 then 'valid'
else 'invalid' end = 'valid';
... thencond = 3
将针对先前案例中尚未匹配的所有行进行评估,而不管parm
- 例如 ifparm = 2013
和的值cond = 3
,您的原始动态版本不会拾取。与2013
你匹配One
and Three
。因此,您需要排除parm
之前用作条件的所有值,然后再查看cond = 3
:
and case
when parm = 2013 and cond = 1 then 'valid'
when parm = 2012 and cond = 2 then 'valid'
when not (parm = 2013 or parm = 2012) and cond = 3 then 'valid'
else 'invalid' end = 'valid';
所以在你的伪代码中,这可能意味着:
select ... from table where condition1 and case
when (<condition1> and <one_new_condition_will_be_added_in_where_clause1>)
then 'valid'
when (<condition2> and <one_new_condition_will_be_added_in_where_clause2>
then 'valid'
when (<condition3> and <one_new_condition_will_be_added_in_where_clause3>)
then 'valid'
when (not (<condition1> or <condition2> or <condition3>)
and <one_new_condition_will_be_added_in_where_clause4>)
then 'valid'
else 'invalid'
end = 'valid'
我不一定说这是一个好主意,只是说它应该可以工作。不知道为什么您的客户端反对动态 SQL(所有这些?查询的某些特定方面?您对数据库的一些影响,例如通过不使用绑定变量?)以及您的真实查询在做什么是不可能知道的如果这种方法合适的话。可能有更好的方法,这可能是我们所知道的改进动态版本......