繁体   English   中英

如何摆脱动态 SQL

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM