oracle forall的使用,看看有哪几种insert

环境:11g

create table emp_copy
as
select empno, ename, job, hiredate from emp where 1 = 2;  

1.整体
--简写
declare
     cursor c_emps is
        select empno, ename, job, hiredate from emp;
     type emp_aat is table of c_emps%rowtype
        index by pls_integer;
     aa_emps emp_aat;

  begin
     open c_emps;
     fetch c_emps bulk collect into aa_emps;
     close c_emps;

     forall i in  1 .. aa_emps.count
        insert /*+ append_values*/ into emp_copy
        values  aa_emps(i);
     dbms_output.put_line(
        to_char(sql%rowcount) || ' rows inserted.'
        );
  end;

等价于:(指定字段)
declare
     cursor c_emps is
        select empno, ename, job, hiredate from emp;
     type emp_aat is table of c_emps%rowtype  ;
       
     aa_emps emp_aat;

  begin
     open c_emps;
     fetch c_emps bulk collect into aa_emps;
     close c_emps;

     forall i in  1 .. aa_emps.count
       insert /*+ append_values*/ into emp_copy
          (empno, ename, job, hiredate)
        values
          (aa_emps(i).empno,
           aa_emps(i).ename,
           aa_emps(i).job,
           aa_emps(i).hiredate);
  end;
  支持append_values


2.指定字段,indices of可以跳过不存在的值
create table emp_copy
  as
  select empno, ename, job, hiredate from emp where 1 = 2;  
  
  select * from emp_copy;
  
  declare
     cursor c_emps is
        select empno, ename, job, hiredate from emp;
     type emp_aat is table of c_emps%rowtype
        index by pls_integer;
     aa_emps emp_aat;

  begin
     /* bulk fetch sample data... */
     open c_emps;
     fetch c_emps bulk collect into aa_emps;
     close c_emps;
     
     forall i in indices of aa_emps
        insert into emp_copy
          (empno, ename, job, hiredate)
        values
          (aa_emps(i).empno,
           aa_emps(i).ename,
           aa_emps(i).job,
           aa_emps(i).hiredate);

     dbms_output.put_line(
        to_char(sql%rowcount) || ' rows inserted.'
        );
  end;
一样,支持/*+ append_values*/实测


3.指定字段,使用动态sql
declare
     cursor c_emps is
     select empno, ename, job, hiredate from emp;
     --这里使不使用index by pls_integer效果一样;
     type emp_aat is table of c_emps%rowtype   index by pls_integer;
     aa_emps emp_aat;
     --动态sql 一样支持append_values
     v_sql varchar2(20000):='insert /*+ append_values*/ into emp_copy (empno, ename, job, hiredate) values(:1,:2,:3,:4)';

  begin
     open c_emps;
     fetch c_emps bulk collect into aa_emps;
     close c_emps;
     forall i in  1 .. aa_emps.count
        execute immediate v_sql using  aa_emps(i).empno,
                                       aa_emps(i).ename,
                                       aa_emps(i).job,
                                       aa_emps(i).hiredate;
  end;

支持append_values;


4.forall 也支持 insert into..select方式,可以指定字段插入
但是不支持append方式
实测这里append和append_values效果一样;
insert /*+append_values*/ into emp_copy
select empno, ename, job, hiredate  from emp where rowid='AAAUVnAAEAAAiOHAAB';


方式1:一次提交
declare
  cursor c_emps is
    select rowid rid from emp;
  v_tab dbms_sql.Urowid_Table;

begin
  open c_emps;
  fetch c_emps bulk collect
    into v_tab;
  close c_emps;

  forall i in 1 .. v_tab.count
    insert 
    into emp_copy
      select empno, ename, job, hiredate from emp where rowid = v_tab(i);          
  dbms_output.put_line(sql%rowcount || ' rows inserted.');  
  commit; --放在sql%rowcount后面,否则得不到行数
end;


方式2:分批提交,相对完整的写法
declare
  cursor c_emps is
    select rowid rid from emp;
  v_tab   dbms_sql.Urowid_Table;
  v_limit pls_integer := 5;
  v_count pls_integer:=0;
begin
  open c_emps;

  loop
    v_count:=v_count+1;
    fetch c_emps bulk collect
      into v_tab limit v_limit;   
      
    forall i in 1 .. v_tab.count
      insert 
      into emp_copy
        select empno, ename, job, hiredate from emp where rowid = v_tab(i);     
    dbms_output.put_line('第'||v_count||'次循环:'||(sql%rowcount) || ' rows inserted.'); 
    commit;
    exit when c_emps%notfound;
  end loop;   
  close c_emps;   
  
exception when
  others then
  dbms_output.put_line(sqlerrm||dbms_utility.format_error_backtrace);
end;

输出:
第1次循环:5 rows inserted.
第2次循环:5 rows inserted.
第3次循环:2 rows inserted.


更新和删除同理可以使用上面的方式

小结:
对于插入操作效率,优先考虑cats,其次merge into+append_values
如果内存不足,则使用批量提交+append_values;
对于批量提交:
如果集合里面的值不连续,那么用indices of;
如果连续就要正常的Insert into values就可以了,
第4种方式不支持append,且查2遍,效率并不好,不推荐;
如果待查询的sql是动态的,就使用动态sql;

对于更新操作效率:
rowid分片效率最高,只是操作稍麻烦点
然后手动查rowid结合批量更新或者merge into
然后自动任务DBMS_PARALLEL_EXECUTE

如有说的不对的地方,还请指正,谢谢
Q:279907389

猜你喜欢

转载自blog.csdn.net/u011165335/article/details/82778857