[英]How can I get rid of dynamic SQL
我的一个 package 机身中有以下动态 SQL
OPEN ccur for
'select c.category
from test_category c
where c.deptid='||PI_N_Dept ||
' and c.category not in ('|| sExcludeCategories ||')';
sExcludeCategories
将包含一组用逗号分隔的整数。 我想消除这个动态的 SQL 语句。 有什么聪明的方法可以做到这一点吗?
我猜你知道你可以将一个变量绑定到PI_N_Dept
以删除那块动态 sql。 不幸的是,对于您的IN
子句和sExcludeCategories
,您无法为 Oracle 中的列表绑定变量(据我所知,至少高达 9.2)
你确实有几个选择。 您当前的解决方案是最简单的。 另一种解决方案是更改过程以接受多个变量并创建 AND 语句列表。
'select c.category
from test_category c
where c.deptid= :PI_N_Dept
and c.category <> :sExcludeCategory1
and c.category <> :sExcludeCategory2
and c.category <> :sExcludeCategory3
';
或者有一个固定的 IN 值列表
'select c.category
from test_category c
where c.deptid= :PI_N_Dept
and c.category not in (:sExcludeCategory1 , :sExcludeCategory2, :sExcludeCategory3)';
如果您只需要 2 个类别,则必须小心。 第三个必须设置为不在 c.category 中的某个值(注意:小心并在此处测试 null 值)
Ask Tom中介绍了另一种解决方案。 这看起来很简单,虽然我没有测试过。 它通过创建一个 function str2tbl() 来工作,它允许您传递一系列用逗号分隔的数字并通过对偶创建一个“表”来执行 IN。
create or replace type myTableType as table of number;
create or replace function str2tbl( p_str in varchar2 ) return myTableType
as
l_str long default p_str || ',';
l_n number;
l_data myTableType := myTabletype();
begin
loop
l_n := instr( l_str, ',' );
exit when (nvl(l_n,0) = 0);
l_data.extend;
l_data( l_data.count ) := ltrim(rtrim(substr(l_str,1,l_n-1)));
l_str := substr( l_str, l_n+1 );
end loop;
return l_data;
end;
你的例子看起来像
'select c.category
from test_category c
where c.deptid= :PI_N_Dept
and c.category not in ( select * from INLIST ( select cast( str2tbl( :sExcludeCategories ) as mytableType ) from dual ) )';
这仅在sExcludeCategories
是数字列表时才有效。 如果引号包含在变量中(并且您无法更改),则必须更改 str2tbl 以处理引号, myTableType
的类型更改为varchar2(10)
或更合适的内容。
总体而言,如果原始 sql 不影响性能,那么为简单起见,我会将其保留为动态 SQL。 维持这样的头痛要少得多。 否则测试str2tbl。 它应该在 Oracle 8 及以上版本中工作。
PS :为了完整起见,我遇到了这篇关于绑定变量的好文章,它涵盖了一些简单的问题,比如虽然没有为 IN 子句使用变量。
我不知道 oracle,但在 SQL 服务器中,获取“拆分” udf 是相当常见的(就像这样- 只是许多可用版本中的一个),它会将 ZCC8D68C551C44A9A6DZ5313E 值转换为列) 到它。 pl-sql 有类似的东西吗?
create or replace type numbertype
as object
(nr number(20,10) )
/
create or replace type number_table
as table of numbertype
/
create or replace procedure tableselect
( p_numbers in number_table
, p_ref_result out sys_refcursor)
is
begin
open p_ref_result for
select *
from employees , (select /*+ cardinality(tab 10) */ tab.nr from table(p_numbers) tab) tbnrs
where id = tbnrs.nr;
end;
/
你可以这样写:
OPEN ccur for
select c.category
from test_category c
where
c.deptid= PI_N_Dept
and c.category not in
(select category_id from categories where <some-condition-that-finds-the-categories-that-should-be-excluded>);
您可以通过将您的值批量复制到一个临时表中来解决这个问题,然后加入该表。 一开始可能听起来有点矫枉过正,但由于这是一种非常常见的模式,你肯定会经常重复使用该代码。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.