在动态 sql 中使用集合

Posted

技术标签:

【中文标题】在动态 sql 中使用集合【英文标题】:Using collection inside dynamic sql 【发布时间】:2017-02-08 08:13:18 【问题描述】:

我正在尝试将 dbms_sql.number_table 从一个过程传递到另一个过程,然后在动态 plsql 块中使用它。但是下面的代码会抛出错误:

错误(6,17):PLS-00306:调用“||”时参数的数量或类型错误

create or replace
procedure proc1( v_in_table_name varchar2,
                 v_in_column_name varchar2,
                 v_in dbms_sql.number_table)
as
plsql_block varchar2(4000);
begin
   plsql_block:='declare

                 begin
                      FORALL INDX IN 1 ..'||v_in.count||'  SAVE EXCEPTIONS 
                       UPDATE '||v_in_table_name||'
                         Set '||v_in_column_name||'=123 WHERE col2='||v_in||'(INDX)||;
                 end';
    execute immediate plsql_block;
end proc1;

【问题讨论】:

【参考方案1】:

您应该进行两项更改: 首先(及其错误情况)是当您将字符串与集合连接时。 如果要将集合发送到 pl/sql 块中,则应使用参数。 其次,您应该在动态 pl\sql 的末尾添加;

create or replace
procedure proc1(v_in dbms_sql.number_table)
as
plsql_block varchar2(4000);
begin
   plsql_block:='declare
                   l_collect dbms_sql.number_table := :number_table ;
                 begin
                      FORALL INDX IN 1 ..'||v_in.count||'  SAVE EXCEPTIONS 
                       UPDATE table_name
                         Set col1=123 WHERE col2=l_collect(INDX);
                 end;';
    execute immediate plsql_block using v_in;
end proc1;

但在所有的变化之后我想问:你真的需要使用动态 pl\sql 吗?

【讨论】:

不确定你在哪里试过因为我有 oracle 11gR2,它给了我这个错误PLS-00457: expressions have to be of SQL types。我会说再试一次并发布工作版本 编译时出现此错误 Error(13,41): PLS-00457: 表达式必须是 SQL 类型【参考方案2】:

不需要使用动态块。我也不认为它也可以工作。你可以这样用;

create or replace
procedure proc1(v_in dbms_sql.number_table)
as
plsql_block varchar2(4000);

l_collect dbms_sql.number_table;

begin

l_collect := v_in;

 FORALL INDX IN 1 ..l_collect.count  SAVE EXCEPTIONS 
      UPDATE table_name
    Set col1=123 
    WHERE col2=l_collect(INDX);

 commit; 
end proc1;

执行:

 SQL> DECLARE
       var   DBMS_SQL.number_table;
       BEGIN
         var (1) := 1;
         var (2) := 2;
         var (3) := 3;
        proc1 (var);
       END;    
     /

PL/SQL procedure successfully completed.

编辑:根据您的编辑,代码如下:

 create or replace procedure proc1 (v_in_table_name     varchar2,
                                   v_in_column_name    varchar2,
                                   v_in                dbms_sql.number_table)
as
   plsql_block   varchar2 (4000);
begin
   plsql_block := q'[ FORALL INDX IN 1 ..v_in.count  SAVE EXCEPTIONS 
                          UPDATE :table_name
                          Set :col1=123 
                          WHERE col2=v_in(INDX)]';

   execute immediate plsql_block using v_in_table_name, v_in_column_name;

   commit;
end proc1;

【讨论】:

我正在动态 plsql 块中进行其他处理,所以我需要在动态块中进行所有处理。 您只是在循环集合内的数据。我也在做同样的事情。我只是将数据处理为一个变量并运行它。动态块的需要在这里没用 我的要求是需要使用动态块 您想使用动态 sql 实现什么。因为无论您想实现什么,都可以使用上述方法完成。 更新语句中的表名是动态的,因此是动态块

以上是关于在动态 sql 中使用集合的主要内容,如果未能解决你的问题,请参考以下文章

MyBatis参数传入集合之foreach动态sql

MyBatis参数传入集合之foreach动态sql

MyBatis中动态sql的模糊搜索foreach实现In集合的用法

MyBatis中动态sql实现传递多个参数并使用if进行参数的判断和实现like模糊搜索以及foreach实现in集合

[mybatis]动态sql_foreach_遍历集合&批量插入

如何从具有 RETURNING 子句的动态 SQL 返回集合