想要将Dynamic PL / SQL查询转换为静态查询

时间:2013-04-05 09:12:52

标签: sql oracle plsql

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

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条款中给出的条件&amp;如果任何一个为真,则在没有在where子句中添加这些条件的情况下给出输出。

希望有人能理解这个问题&amp;会给出解决方案。 在此先感谢。

2 个答案:

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

...然后cond = 3将针对之前案例中尚未匹配的所有行进行评估,而不考虑parm的值 - 例如如果parm = 2013cond = 3,您的原始动态版本将无法获取。使用2013,您将匹配OneThree。因此,您需要排除之前用作条件的所有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(所有这些?你的查询的某些特定方面?你对数据库产生了一些影响,例如通过不使用绑定变量?)以及你真正的查询正在做什么它是不可能知道的如果这种方法合适。可能有更好的方法,这可能会改善我们所知道的动态版本......

答案 1 :(得分:0)

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

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

并在那里实施评估。我不确定你对性能的评价,但你可能对基于功能的索引感兴趣以提高你的表现。

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