Oracle-FORALL与BULK COLLECT语句

sqlplus 在运行plsql过程化的sql语句时(程序块),使用plsql引擎执行过程化的程序,而将sql语句发送给sql引擎来执行。sql语句执行完后将结果集再发送给plsql引擎。这种plsql和sql引擎之间的交互,称上下文交换。每增加一次引擎之间的交互,会增加额外的开销。执行效率就会降低。

BULK COLLECT:用来增强sql引擎到plsql引擎之间的交互。

FORALL:用来增强plsql引擎到sql引擎的交互。

一、BUIL COLLECT

BUIL COLLECT 子句会批量检索查询结果,即一次性将结果集绑定到一个集合变量中,从sql引擎发送到plsql引擎。

通常在 select..into..、fetch..into.. 、returning..into..子句中使用bulk collect。

①在select into子句中使用

declare
    type emp_type is record (
       empno emp.empno@type,
       ename emp.ename%type,
       hiredate emp.hiredate%type);
    
    type nested_emp_type is table of emp_type;
    emp_tab nested_emp_type;
begin
    select * bulk collect into emp_tab from emp;
    for i in emp_tab.first..emp_tab.last 
        loop
            dbms_output.put_line(emp_tab(i).empno);
            dbms_output.put_line(emp_tab(i).empno);
            dbms_output.put_line(emp_tab(i).empno);
        end loop;
 end;
/

说明:使用bulk collect 一次即可提取所有行并绑定到记录变量------->批量绑定。

②在fetch into 中使用

在游标中可以使用bulk collect 一次取出一个数据集合,比用游标单条取数据效率高,尤其在网络不好的情况下。

语法:
fetch.... bulk collect into ......[limit row_number];

在使用bulk collect子句时,对于集合类型会自动对其进行初始化以及扩展,因此如果使用bulk collect 子句操作集合,则无需对集合进行初始化以及扩展,由于bulk collect批量特性,如果数据量较大,而集合在此时又自动扩展,为避免过大的数据集造成性能下降,因此可使用limit子句限制一次提取的数据量。limit子句只允许在fetch操作语句中。

declare
 cursor emp_cur is select empno,ename,hiredate from emp;

 type emp_type is record (
  empno emp.empno%type,
  ename emp.ename%type,
  hiredate emp.ename%type);

 type nested_emp_type is table of emp_type;

 emp_tab nested_emp_type;

 v_limit pls_integer:=5;
 v_counter pls_integer:=0;

begin
 open emp_cur;
 loop
     fetch emp_cur bulk collect into emp_tab limit v_limit;
     exit when emp_tab.count=0;-----此时游标退出使用 ,不是emp_cur%notfound
     v_counter:=v_counter+1;-----记录fetch的次数
 
     for i in emp_tab.first..emp_tab.last 
     loop
        dbms_output.put_line(emp_tab(i).empno);
        dbms_output.put_line(emp_tab(i).ename);
        dbms_output.put_line(emp_tab(i).hiredate);
      end loop;
 end loop;
 close emp_cur;
 dbms_output.put_line('总共获取次数:'||v_counter);
end;





③在returning into

bulk collect除了与select into,fetch进行批量绑定之外,还可以与insert、update、delete语句结合使用,当与这几个dml语句结合使用时,需要returning into 子句实现批量绑定。

declare
 type emp_type is record(
 empno emp.empno%type,
 ename emp.ename%type,
 hiredate emp.hiredate%type);
 
type nested_emp_type is table of emp_type;
emp_tab nested_emp_type;
begin
    delete from emp where deptno=20 returning empno,ename,hiredate bulk collect into emp_tab;
    dbms_output.put_line('删除'||sql%rowcount||'行记录'):
    commit;

    if emp_tab.count>0 then ----当集合变量不为空,输出
     for i in emp_tab.first..emp_tab.last loop
        dbms_output.put_line('删除记        
        录:'||emp_tab(i).empno||chr(32)||emp_tab(i).ename||chr(32)||emp_tab(i).hiredate);
      end loop;
end if;
end;

BUIL COLLECT 注意事项:

1、目标对象必须是集合类型。

2、只能在服务端的程序中使用bulk collect 。在客户端不支持。

3、不能对使用字符串类型作键的关联数组使用BULK COLLECT子句。

4、复合目标(如对象类型)不能在RETURNING INTO子句中使用。

5、如果有多个隐式的数据类型转换的情况存在,多重复合目标就不能在BULK COLLECT INTO子句中使用。

6、如果有一个隐式的数据类型转换,复合目标的集合(如对象类型集合)就不能用于BULK COLLECTINTO子句中。

 

二\、FORALL

语法:
forall index_name in {

lower_bound..upper_bound
| indices of collection_name[between lower_bound and upper_bound]
| values of index_collection
}
[save exceptions] dml_statement;

说明:
index_name:一个无需声明的标识符,作为集合的下标使用。
lower_bound..upper_bound:数字表达式,来指定一组连续有效的索引数字下限和上限。该表达式只需解析一次。
INDICES OF collection_name:用于指向稀疏数组的实际下标。跳过没有赋值的元素,例如被 DELETE 的元素,NULL 也算值。

VALUES OF index_collection_name:把该集合中的值当作下标,且该集合值的类型只能是 PLS_INTEGER/BINARY_INTEGER。

SAVE EXCEPTIONS:可选关键字,表示即使一些DML语句失败,直到FORALL LOOP执行完毕才抛出异常。可以使用SQL%BULK_EXCEPTIONS 查看异常信息。

dml_statement:静态语句,例如:UPDATE或者DELETE;或者动态(EXECUTE IMMEDIATE)DML语句

①FORALL批量插入、修改、删除数据

create table tmp_tab(
 id number(5),
 name varchar2(50));
----批量插入
declare
    type  tb_table_type is table of tmp_tab%rowtype index by binary_integer;
    tb_table tb_table_type;
    
begin
     for i in 1..100 loop
        tb_table(i).id=i;
        tb_table(i).name='name'||i;
      end loop;
     
      forall i in 1..tb_table.count
      insert into tmp_tab values tb_table(i);
end;
--------批量修改
declare  
    type  tb_table_type is table of tmp_tab%rowtype index by binary_integer;
    tb_table tb_table_type;
    
begin
    for i in 1..100 loop
        tb_table(i).id=i;
        tb_table(i).name:='my_name'||i;
    end loop;
    forall i in tb_table.count update tmp_tab set row=tb_table(i) where t.id=tb_table(i).id;
end;
----------批量删除
declare  
    type  tb_table_type is table of tmp_tab%rowtype index by binary_integer;
    tb_table tb_table_type;
    
begin
    for i in 1..100 loop
        tb_table(i).id=i;
        tb_table(i).name:='my_name'||i;
    end loop;
    forall i in 1..tb_table.count delete from tmp_tab where id =tb_table(i).id;
end;



 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值