批量SQL之 BULK COLLECT 子句

2021-08-26 21:32:38 字數 4441 閱讀 3865

bulk collect 子句會批量檢索結果,即一次性將結果集繫結到乙個集合變數中,並從sql引擎傳送到pl/sql引擎。通常可以在select into、

fetch into以及returning into子句中使用bulk collect。本文將逐一描述bulk collect在這幾種情形下的用法。

有關forall語句的用法請參考:批量sql之 forall 語句

一、bulk collect批量繫結的示例

--下面的示例中使用了bulk collect將得到的結果集繫結到記錄變數中 declare type emp_rec_type is record --宣告記錄型別 ( empno emp.empno%type ,ename emp.ename%type ,hiredate emp.hiredate%type ); type nested_emp_type is table of emp_rec_type; --宣告記錄型別變數 emp_tab nested_emp_type; begin select empno, ename, hiredate bulk collect into emp_tab --使用bulk collect 將所得的結果集一次性繫結到記錄變數emp_tab中 from emp; for i in emp_tab.first .. emp_tab.last loop dbms_output.put_line('current record is '||emp_tab(i).empno||chr(9)||emp_tab(i).ename||chr(9)||emp_tab(i).hiredate); end loop; end; --上面的例子可以通過for 迴圈和普通的select into來實現,那兩者之間的差異呢? --差異是for迴圈的select into逐行提取並繫結到記錄變數,而bulk collect則一次即可提取所有行並繫結到記錄變數。即謂批量繫結。

二、使用limit限制fetch資料量

在使用bulk collect 子句時,對於集合型別,如巢狀表,聯合陣列等會自動對其進行初始化以及擴充套件(如下示例)。因此如果使用bulk

collect子句操作集合,則無需對集合進行初始化以及擴充套件。由於bulk collect的批量特性,如果資料量較大,而集合在此時又自動擴充套件,為避

免過大的資料集造成效能下降,因此使用limit子句來限制一次提取的資料量。limit子句只允許出現在fetch操作語句的批量中。

用法:fetch ... bulk collect into ... [limit rows]

declare cursor emp_cur is select empno, ename, hiredate from emp; type emp_rec_type is record ( empno emp.empno%type ,ename emp.ename%type ,hiredate emp.hiredate%type ); type nested_emp_type is table of emp_rec_type; -->定義了基於記錄的巢狀表 emp_tab nested_emp_type; -->定義集合變數,此時未初始化 v_limit pls_integer := 5; -->定義了乙個變數來作為limit的值 v_counter pls_integer := 0; begin open emp_cur; loop fetch emp_cur bulk collect into emp_tab -->fetch時使用了bulk collect子句 limit v_limit; -->使用limit子句限制提取資料量 exit when emp_tab.count = 0; -->注意此時游標退出使用了emp_tab.count,而不是emp_cur%notfound v_counter := v_counter + 1; -->記錄使用limit之後fetch的次數 for i in emp_tab.first .. emp_tab.last loop dbms_output.put_line( 'current record is '||emp_tab(i).empno||chr(9)||emp_tab(i).ename||chr(9)||emp_tab(i).hiredate); end loop; end loop; close emp_cur; dbms_output.put_line( 'the v_counter is ' || v_counter ); end;

三、returning 子句的批量繫結

bulk collect除了與select,fetch進行批量繫結之外,還可以與insert,delete,update語句結合使用。當與這幾個dml語句結合時,我們

需要使用returning子句來實現批量繫結。

--下面示例中從表emp中刪除所有deptno=20的記錄 declare type emp_rec_type is record ( empno emp.empno%type ,ename emp.ename%type ,hiredate emp.hiredate%type ); type nested_emp_type is table of emp_rec_type; emp_tab nested_emp_type; -- v_limit pls_integer := 3; -- v_counter pls_integer := 0; begin delete from emp where deptno = 20 returning empno, ename, hiredate -->使用returning 返回這幾個列 bulk collect into emp_tab; -->將前面返回的列的資料批量插入到集合變數 dbms_output.put_line( 'deleted ' || sql%rowcount || ' rows.' ); commit; if emp_tab.count > 0 then -->當集合變數不為空時,輸出所有被刪除的元素 for i in emp_tab.first .. emp_tab.last loop dbms_output. put_line( 'current record ' || emp_tab( i ).empno || chr( 9 ) || emp_tab( i ).ename || chr( 9 ) || emp_tab( i ).hiredate || ' has been deleted' ); end loop; end if; end;

四、forall與bulk collect 綜合運用

forall與bulk collect是實現批量sql的兩個重要方式,我們可以將其結合使用以提高效能。下面的示例即是兩者的總和運用。

drop table tb_emp; create table tb_emp as -->建立表tb_emp select empno, ename, hiredate from emp where 1 = 2; declare cursor emp_cur is -->宣告游標 select empno, ename, hiredate from emp; type nested_emp_type is table of emp_cur%rowtype; -->基於游標的巢狀表型別 emp_tab nested_emp_type; -->宣告巢狀變數 begin select empno, ename, hiredate bulk collect into emp_tab -->bulk collect批量提取資料 from emp where sal > 1000; forall i in 1 .. emp_tab.count -->使用forall語句將變數中的資料插入到表tb_emp insert into (select empno, ename, hiredate from tb_emp) values emp_tab( i ); commit; dbms_output.put_line( 'the total ' || emp_tab.count || ' rows has been inserted to tb_emp' ); end;

五、bulk collect的限制

1、不能對使用字串型別作鍵的關聯陣列使用bulk collect 子句。

2、只能在伺服器端的程式中使用bulk collect,如果在客戶端使用,就會產生乙個不支援這個特性的錯誤。

3、bulk collect into 的目標物件必須是集合型別。

4、復合目標(如物件型別)不能在returning into 子句中使用。

5、如果有多個隱式的資料型別轉換的情況存在,多重復合目標就不能在bulk collect into 子句中使用。

6、如果有乙個隱式的資料型別轉換,復合目標的集合(如物件型別集合)就不能用於bulk collectinto 子句中。

六、更多參考

批量sql之 forall 語句

pl/sql 集合的初始化與賦值

pl/sql 聯合陣列與巢狀表

pl/sql 變長陣列

pl/sql --> pl/sql記錄

sql tuning 步驟

高效sql語句必殺技

父游標、子游標及共享游標

繫結變數及其優缺點

dbms_xplan之display_cursor函式的使用

dbms_xplan之display函式的使用

執行計畫中各字段各模組描述

使用 explain plan 獲取sql語句執行計畫

批量更新sql 批量update sql

批量更新sql 批量update sql 批量更新表時,update乙個表的列時,需要依賴另外的表,這種依賴可以是where條件子句,也可以要update的field的值依賴另外的表 通常有兩種做法 1.使用儲存過程 2.在程式 裡逐條迴圈執行 這裡給出一種更高效 簡潔的做法,批量更新sql 一句s...

sql批量更新

批量更新 1 statement statement cn.createstatement addbatch sql1 addbatch sql2 executebatch 乙個statement物件,可以執行多個sql語句以後,批量更新。這多個語句可以是delete update insert等或...

批量插入SQL

sql語句是有長度限制,在進行資料合併在同一sql中務必不能超過sql長度限制,通過max allowed packet配置可以修改,預設是1m,測試時修改為8m。事務需要控制大小,事務太大可能會影響執行的效率。mysql有 innodb log buffer size 配置項,超過這個值會把inn...