在 Oracle 中使用 FORALL 进行更新和插入

问题描述 投票:0回答:3

我是 PL/SQL 新手。 我有一个类似的程序:

 create or replace procedure insert_charge is
   v_count       number;
 begin
 
   for i in (select t.name, t.hire_date, t.salary
               from emp t
              where t.create_date >= (sysdate - 30)
                and t.salary = 0) loop
 
       insert into charge
         (name, hire_date, salary)
       values
         (i.name, hire_date, salary);
       commit;
     
       update emp l
          set l.status = 1
        where l.name = i.name
          and l.status = 0
          and l.hire_date = i.hire_date;
       commit;
   end loop;
 exception
   when others then
     rollback;
 end insert_charge;

如何使用FORALL语句来代替这个?

sql oracle plsql
3个回答
2
投票

FORALL
还有一些额外的任务;即定义一个集合来定义大块区域,并定义该集合类型的变量来包含实际数据。作为安全值,您应该对一次获取的数量设置限制。 Bulk Collect/Forall 是速度与内存的权衡。并且在某个点(取决于您的配置)收益递减。除了您使用的内存之外,数据库中的其他进程也无法使用它。与您的其他查询很好地吻合。然后正如 @Littlefoot 指出的那样,不要压制异常,记录它们并重新加注。最后,关于提交的注释。 **不要在每个 DML 语句之后提交,您可能需要花一些时间来调查[事务][1]。考虑到这一点,你的程序就变成了这样:

create or replace procedure insert_charge is
     cursor c_emp_cur is 
            select t.name, t.hire_date, t.salary
               from emp t
              where t.create_date >= (sysdate - 30)
                and t.salary = 0; 
                
     type c_emp_array_t is table of c_emp%rowtype ;  -- define collection for rows selected
     
     k_emp_rows_max constant integer := 500;         -- defines the maximum rows per fetch
     l_emp_list     c_emp_array_t;                   -- define variable of rows collection 
 begin
    open c_emp_cur; 
       
    loop 
        fetch c_emp_cur                              -- fetch up to LIMIT rows from cursor
         bulk collect 
         into l_emp_collect
        limit k_emp_rows_max; 
        
        forall i in 1 .. l_emp_collect.count         -- run insert for ALL rows in the collection
            insert into charge(name, hire_date, salary)
                 values( l_emp_collect(i).name 
                       , l_emp_collect(i).hire_date
                       , l_emp_collect(i).salary);
                       
        forall i in 1 .. l_emp_collect.count        -- run update for ALL rows in the collection          
            update emp l
               set l.status = 1
             where l.name = l_emp_collect(i).name
               and l.status = 0
               and l.hire_date = l_emp_collect(i).hire_date;
            
    exit when c_emp_cur%notfound;                     -- no more rows so exit
    end loop;
    
    close c_emp_cur; 
    commit;                                          -- JUST 1 COMMIT; 
 exception
   when others then
        generate_exception_log ('insert_charge', sysdate, sql_errm );    --ASSUMED Anonomous Transaction procedure for exception log table. 
        raise;
 end insert_charge;      

免责声明:未经测试。 [1]:https://www.techopedia.com/definition/16455/transaction-databases


2
投票

你不能。

FORALL 语句运行一个 DML 语句多次

ONE DML 语句。您有两个(更新和插入)。


截至您编写的代码:

  • COMMIT
    移出循环
  • 删除
    when others
    “处理程序”,因为它不处理任何内容。如果发生错误,Oracle 将默默回滚并报告过程成功完成,而实际上 - 失败

0
投票

el forall con 更新 tiene 错误:

LS-00436:实现限制:无法引用 BULK In-BIND 记录表的字段 ORA-06550: 第 21 行,第 43 列: PLS-00382:表达式类型错误 ORA-06550: 第 20 行,第 43 列: PLS-00436:实现限制:无法引用 BULK In-BIND 记录表的字段 ORA-06550: 第 20 行,第 43 列: PLS-00382:表达式类型错误 ORA-06550: 第 19 行,第 43 列: PLS-00436:实现限制:无法引用 BULK In-BIND 记录表的字段 ORA-06550: 第 19 行,第 43 列: PLS-00382:表达式类型错误 ORA-06550: 第 18 行,第 43 列: PLS-00436:实现限制:无法引用 BULK In-BIND 记录表的字段 ORA-06550: 第 18 行,第 43 列: PLS-00382:表达式类型错误 ORA-06550: 第 17 行,第 43 列: PLS-00436:实现限制:无法引用 BULK In-BIND 记录表的字段 ORA-06550: 第 17 行,第 43 列: PLS-00382:表达式为

© www.soinside.com 2019 - 2024. All rights reserved.