sql - 我怎样才能摆脱动态SQL

标签 sql oracle plsql

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

最佳答案

我猜你知道你可以将变量绑定(bind)到 PI_N_Dept 以删除那段动态 sql。不幸的是,对于您的 IN 子句和 sExcludeCategories,您无法为 Oracle 中的列表绑定(bind)变量(据我所知至少达到 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 中的值(注意:小心并在此处测试空值)

另一种解决方案在 Ask Tom 中提出.这看起来很简单,虽然我还没有测试过。它通过创建一个函数 str2tbl() 来工作,该函数允许您传递一系列以逗号分隔的数字,并通过 dual 创建一个“表”来执行 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:为了完整起见,我遇到了 this nice article on binding vars涵盖了一些简单的问题,例如不对 IN 子句使用变量。

关于sql - 我怎样才能摆脱动态SQL,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/670922/

相关文章:

c# - 无法将类型 'bool' 隐式转换为 'system.threading.tasks.task bool'

mysql - 合并查询结果,优化?

sql - 如何将序列号更新到包含数据的现有表

oracle - 如何执行 DBMS_METADATA.GET_DEPENDENT_DLL 的即时输出?

oracle - PL/SQL 匿名 block 与 PL/SQL 过程 - ORA-01418 : specified index does not exist

数据库模式的 SQL 查询

javascript - Oracle Jet 不显示来自 Web 服务的数据

mysql - Oracle 的 group by 和 count 查询问题

使用左外连接时 Oracle 分区修剪不起作用

oracle - 调用HTTP页面时如何给出用户名和密码?