要将动态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'