-1

在我的项目中,有一个冗长的动态查询,如下所示 -

basic_query varchar2(1000);
final_query varchar2(1500);
where_clause varchar2(500) default null;

basic_query :=<select ...from table where ....>

If(<condition1>)
    then 
    where_clause := <one_new_condition_will_be_added_in_where_clause1>
elsif(<condition2>)
    then 
    where_clause := <one_new_condition_will_be_added_in_where_clause2>
elsif(<condition3>)
    then 
    where_clause := <one_new_condition_will_be_added_in_where_clause3>
else  
    where_clause := <one_new_condition_will_be_added_in_where_clause4>
endif;



final_query :=basic_query || where_clause || '<group_by_clause'> || <'order_by_clause'>;

execute immediate final_query;

现在我的客户想要将此动态查询转换为静态查询。我已经尝试过使用 CASE,但它不能正常工作。

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(<condition1> and <one_new_condition_will_be_added_in_where_clause3>)
    then 'valid'
when(<condition2> and <one_new_condition_will_be_added_in_where_clause4>
        then 'valid'
    else 'invalid'
end;)='valid

它正在检查 CASE 子句中给出的条件,如果其中任何一个为真,它会给出输出而不在 where 子句中添加这些条件。

希望有人能理解这个问题并给出解决方案。提前致谢。

4

2 回答 2

1

正如我在评论中所说,原则上使用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你匹配Oneand 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(所有这些?查询的某些特定方面?您对数据库的一些影响,例如通过不使用绑定变量?)以及您的真实查询在做什么是不可能知道的如果这种方法合适的话。可能有更好的方法,这可能是我们所知道的改进动态版本......

于 2013-04-05T12:08:29.257 回答
0

我建议您在代码中使用 PL/SQL 函数。

select ...from table where 'Y' = IsRecordValid(...all relevant values in conditions...);

并在那里实施评估。我不确定您对性能的考虑,但您可能对基于函数的索引感兴趣以提高您的性能。

其他方法是使用dbms_sql包,您可以使用它来创建动态 SQL,但几乎保留了静态查询的所有优点。

于 2013-04-05T09:59:30.687 回答