一尘不染

如何摆脱动态SQL

sql

我的包主体之一中包含以下动态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语句。有什么聪明的方法可以做到这一点吗?


阅读 157

收藏
2021-05-30

共1个答案

一尘不染

我猜你知道你可以绑定一个变量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中
提供了另一个解决方案。这看起来很简单,尽管我还没有测试过。它通过创建一个函数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以处理引号,并更改myTableTypeto的类型varchar2(10)或更合适的名称。

总体而言,如果原始sql不影响性能,那么为了简单起见,我将其保留为动态SQL。保持头痛几乎没有。否则,请测试str2tbl。它应该在Oracle
8及更高版本中工作。

PS
:仅出于完整性考虑,我遇到了一篇有关绑定var的不错的文章,该文章涵盖了一些简单的问题,例如虽然没有对IN子句使用变量。

2021-05-30