要将动态PL/SQL查询转换为静态查询吗

要将动态PL/SQL查询转换为静态查询吗,sql,oracle,plsql,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

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

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;
basic_查询varchar2(1000);
最终查询varchar2(1500);
其中,第2(500)条默认为空;
基本查询:=
If()
然后
其中,条款:=
elsif()
然后
其中,条款:=
elsif()
然后
其中,条款:=
其他的
其中,条款:=
endif;

final_query:=basic_query | | where_子句| |'我建议您在代码中使用PL/SQL函数

select ...from table where 'Y' = IsRecordValid(...all relevant values in conditions...);
并在那里进行评估。我不确定您对性能的考虑,但您可能对基于函数的索引感兴趣,以提高性能


另一种方法是使用dbms\U sql包,您可以使用该包动态创建sql,但保留静态查询的几乎所有好处。

正如我在一篇评论中所说,原则上使用
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';
…然后,无论
parm
的值是多少,都将对先前案例中尚未匹配的所有行计算
cond=3
——例如,如果
parm=2013
cond=3
,则原始动态版本不会选择这些行。使用
2013
您将匹配
1
三个
。因此您需要排除前面用作条件的所有
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'
从条件1和案例所在的表中选择
何时(及)
然后“有效”
何时(及
然后“有效”
何时(及)
然后“有效”
何时(不是(或)
及)
然后“有效”
否则“无效”
结束='有效'

我并不是说这是一个好主意,只是说它应该起作用。不知道为什么您的客户机反对动态SQL(所有这些?您查询的某些特定方面?您对数据库的一些影响,例如,不使用绑定变量?)而你真正的查询是做什么的,不可能知道这种方法是否合适。可能有更好的方法,这可能是改进我们所知道的动态版本…

你的“新”查询似乎也是动态的-
。目前这个问题太模糊了,我不知道问了什么。而且,“现在,我的客户希望将此动态查询转换为静态查询“-为什么你的客户要告诉你如何编写代码?原则上,你用
案例
所做的工作是可行的,因此我认为在你发布的简化过程中丢失了一些细节。我怀疑原始版本中的最终
else
版本过于宽松,因为它必须否定之前的所有条件(但由于您重复了条件1和条件2,所以不清楚您是否在这样做,这看起来根本不正确)。也无法判断动态SQL在这里是否合适,这取决于实际情况。如果是,那么我还将询问您的客户为什么不同意。切换的原因可能会告知另一种方法。此问题称为“动态WHERE子句”。转到ASKToM A,您会发现关于它的几篇文章。告诉客户,只要代码产生了有效的结果,并且在合理的时间内执行,它的业务就不关它的事了。(我们曾经有一个客户需求来查看产品的源代码,以确保它是真正地用C++编写的。“。当我们问为什么(准备解雇他们)时,回答是“我们组织中的所有软件都必须用C++编写”。当被问到MS-DOS(很久以前是:-)是用什么语言编写的时,他们给了我们一种极度恐惧的表情。我不知道微软是否回答过他们的问题。我知道我们从来没有回答过:-).谢谢你的回复。有没有使用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 (<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'