BULK COLLECT 句は、結果セット全体を 1 回の往復で 1 つ以上のコレクションにロードします。行数が多いクエリの場合、この方法によりデータベースサーバーとクライアント間での行ごとのコンテキストスイッチが発生しないため、パフォーマンスの劣化を回避できます。
この句は以下の文で使用できます。
SELECT INTO 文と BULK COLLECT
SELECT INTO 文の詳細については、SELECT INTO ドキュメントをご参照ください。
構文:
SELECT select_expressions BULK COLLECT INTO collection [, ...]
FROM ... ;コレクションのルール:
コレクションが 1 つの場合、単一フィールドまたは RecordType を保持できます。
複数のコレクションを指定する場合、各コレクションは単一フィールドを保持する必要があります。
select_expressionsは、対象となるすべてのコレクションと、個数・順序・型の互換性において一致している必要があります。
例
例 1:複数の単一フィールドの連想配列
この例では、emp テーブルのすべての列を、列ごとに別々の連想配列に収集します。
DECLARE
TYPE empno_tbl IS TABLE OF emp.empno%TYPE INDEX BY BINARY_INTEGER;
TYPE ename_tbl IS TABLE OF emp.ename%TYPE INDEX BY BINARY_INTEGER;
TYPE job_tbl IS TABLE OF emp.job%TYPE INDEX BY BINARY_INTEGER;
TYPE hiredate_tbl IS TABLE OF emp.hiredate%TYPE INDEX BY BINARY_INTEGER;
TYPE sal_tbl IS TABLE OF emp.sal%TYPE INDEX BY BINARY_INTEGER;
TYPE comm_tbl IS TABLE OF emp.comm%TYPE INDEX BY BINARY_INTEGER;
TYPE deptno_tbl IS TABLE OF emp.deptno%TYPE INDEX BY BINARY_INTEGER;
t_empno EMPNO_TBL;
t_ename ENAME_TBL;
t_job JOB_TBL;
t_hiredate HIREDATE_TBL;
t_sal SAL_TBL;
t_comm COMM_TBL;
t_deptno DEPTNO_TBL;
BEGIN
SELECT empno, ename, job, hiredate, sal, comm, deptno BULK COLLECT
INTO t_empno, t_ename, t_job, t_hiredate, t_sal, t_comm, t_deptno
FROM emp;
DBMS_OUTPUT.PUT_LINE('EMPNO ENAME JOB HIREDATE ' ||
'SAL ' || 'COMM DEPTNO');
DBMS_OUTPUT.PUT_LINE('----- ------- --------- --------- ' ||
'-------- ' || '-------- ------');
FOR i IN 1..t_empno.COUNT LOOP
DBMS_OUTPUT.PUT_LINE(t_empno(i) || ' ' ||
RPAD(t_ename(i),8) || ' ' ||
RPAD(t_job(i),10) || ' ' ||
TO_CHAR(t_hiredate(i),'DD-MON-YY') || ' ' ||
TO_CHAR(t_sal(i),'99,999.99') || ' ' ||
TO_CHAR(NVL(t_comm(i),0),'99,999.99') || ' ' ||
t_deptno(i));
END LOOP;
END;出力:
EMPNO ENAME JOB HIREDATE SAL COMM DEPTNO
----- ------- --------- --------- -------- -------- ------
7369 SMITH CLERK 17-DEC-80 800.00 .00 20
7499 ALLEN SALESMAN 20-FEB-81 1,600.00 300.00 30
7521 WARD SALESMAN 22-FEB-81 1,250.00 500.00 30
7566 JONES MANAGER 02-APR-81 2,975.00 .00 20
7654 MARTIN SALESMAN 28-SEP-81 1,250.00 1,400.00 30
7698 BLAKE MANAGER 01-MAY-81 2,850.00 .00 30
7782 CLARK MANAGER 09-JUN-81 2,450.00 .00 10
7788 SCOTT ANALYST 19-APR-87 3,000.00 .00 20
7839 KING PRESIDENT 17-NOV-81 5,000.00 .00 10
7844 TURNER SALESMAN 08-SEP-81 1,500.00 .00 30
7876 ADAMS CLERK 23-MAY-87 1,100.00 .00 20
7900 JAMES CLERK 03-DEC-81 950.00 .00 30
7902 FORD ANALYST 03-DEC-81 3,000.00 .00 20
7934 MILLER CLERK 23-JAN-82 1,300.00 .00 10例 2:%ROWTYPE RecordType の単一連想配列(推奨)
%ROWTYPE RecordType を使用した単一のコレクションにより、宣言コードを減らしつつ同じ結果を得られます。
DECLARE
TYPE emp_tbl IS TABLE OF emp%ROWTYPE INDEX BY BINARY_INTEGER;
t_emp EMP_TBL;
BEGIN
SELECT * BULK COLLECT INTO t_emp FROM emp;
DBMS_OUTPUT.PUT_LINE('EMPNO ENAME JOB HIREDATE ' ||
'SAL ' || 'COMM DEPTNO');
DBMS_OUTPUT.PUT_LINE('----- ------- --------- --------- ' ||
'-------- ' || '-------- ------');
FOR i IN 1..t_emp.COUNT LOOP
DBMS_OUTPUT.PUT_LINE(t_emp(i).empno || ' ' ||
RPAD(t_emp(i).ename,8) || ' ' ||
RPAD(t_emp(i).job,10) || ' ' ||
TO_CHAR(t_emp(i).hiredate,'DD-MON-YY') || ' ' ||
TO_CHAR(t_emp(i).sal,'99,999.99') || ' ' ||
TO_CHAR(NVL(t_emp(i).comm,0),'99,999.99') || ' ' ||
t_emp(i).deptno);
END LOOP;
END;出力:
EMPNO ENAME JOB HIREDATE SAL COMM DEPTNO
----- ------- --------- --------- -------- -------- ------
7369 SMITH CLERK 17-DEC-80 800.00 .00 20
7499 ALLEN SALESMAN 20-FEB-81 1,600.00 300.00 30
7521 WARD SALESMAN 22-FEB-81 1,250.00 500.00 30
7566 JONES MANAGER 02-APR-81 2,975.00 .00 20
7654 MARTIN SALESMAN 28-SEP-81 1,250.00 1,400.00 30
7698 BLAKE MANAGER 01-MAY-81 2,850.00 .00 30
7782 CLARK MANAGER 09-JUN-81 2,450.00 .00 10
7788 SCOTT ANALYST 19-APR-87 3,000.00 .00 20
7839 KING PRESIDENT 17-NOV-81 5,000.00 .00 10
7844 TURNER SALESMAN 08-SEP-81 1,500.00 .00 30
7876 ADAMS CLERK 23-MAY-87 1,100.00 .00 20
7900 JAMES CLERK 03-DEC-81 950.00 .00 30
7902 FORD ANALYST 03-DEC-81 3,000.00 .00 20
7934 MILLER CLERK 23-JAN-82 1,300.00 .00 10FETCH 文と BULK COLLECT
FETCH 文の詳細については、カーソルドキュメントをご参照ください。
通常の FETCH が 1 行ずつ返すのに対し、FETCH BULK COLLECT はカーソルの結果セットから残りのすべての行を 1 回の呼び出しで対象コレクションに取得します。結果セット全体がメモリにロードされるため、結果セットが大きい可能性がある場合は LIMIT 句を使用してメモリ使用量を制限してください。
構文:
FETCH cursor_name BULK COLLECT INTO collection [, ...] [ LIMIT n ];パラメーター:
| パラメーター | 説明 |
|---|---|
cursor_name | オープン済みのカーソル。その SELECT リストは、対象コレクションと個数・順序・型の互換性において一致している必要があります |
collection | 対象コレクション。単一コレクションは単一フィールドまたは RecordType を保持できる。複数コレクションの場合は、それぞれが単一フィールドを保持する必要がある |
LIMIT n | 1 回の FETCH 呼び出しで返される最大行数。コレクションのサイズを制限することでメモリ消費量をコントロールします |
例:%ROWTYPE 連想配列への FETCH BULK COLLECT
DECLARE
TYPE emp_tbl IS TABLE OF emp%ROWTYPE INDEX BY BINARY_INTEGER;
t_emp EMP_TBL;
CURSOR emp_cur IS SELECT * FROM emp;
BEGIN
OPEN emp_cur;
FETCH emp_cur BULK COLLECT INTO t_emp;
CLOSE emp_cur;
DBMS_OUTPUT.PUT_LINE('EMPNO ENAME JOB HIREDATE ' ||
'SAL ' || 'COMM DEPTNO');
DBMS_OUTPUT.PUT_LINE('----- ------- --------- --------- ' ||
'-------- ' || '-------- ------');
FOR i IN 1..t_emp.COUNT LOOP
DBMS_OUTPUT.PUT_LINE(t_emp(i).empno || ' ' ||
RPAD(t_emp(i).ename,8) || ' ' ||
RPAD(t_emp(i).job,10) || ' ' ||
TO_CHAR(t_emp(i).hiredate,'DD-MON-YY') || ' ' ||
TO_CHAR(t_emp(i).sal,'99,999.99') || ' ' ||
TO_CHAR(NVL(t_emp(i).comm,0),'99,999.99') || ' ' ||
t_emp(i).deptno);
END LOOP;
END;出力:
EMPNO ENAME JOB HIREDATE SAL COMM DEPTNO
----- ------- --------- --------- -------- -------- ------
7369 SMITH CLERK 17-DEC-80 800.00 .00 20
7499 ALLEN SALESMAN 20-FEB-81 1,600.00 300.00 30
7521 WARD SALESMAN 22-FEB-81 1,250.00 500.00 30
7566 JONES MANAGER 02-APR-81 2,975.00 .00 20
7654 MARTIN SALESMAN 28-SEP-81 1,250.00 1,400.00 30
7698 BLAKE MANAGER 01-MAY-81 2,850.00 .00 30
7782 CLARK MANAGER 09-JUN-81 2,450.00 .00 10
7788 SCOTT ANALYST 19-APR-87 3,000.00 .00 20
7839 KING PRESIDENT 17-NOV-81 5,000.00 .00 10
7844 TURNER SALESMAN 08-SEP-81 1,500.00 .00 30
7876 ADAMS CLERK 23-MAY-87 1,100.00 .00 20
7900 JAMES CLERK 03-DEC-81 950.00 .00 30
7902 FORD ANALYST 03-DEC-81 3,000.00 .00 20
7934 MILLER CLERK 23-JAN-82 1,300.00 .00 10EXECUTE IMMEDIATE 文と BULK COLLECT
動的 SQL 文によって返された行を収集するには、EXECUTE IMMEDIATE で BULK COLLECT を使用します。
構文:
EXECUTE IMMEDIATE 'sql_expression'
BULK COLLECT INTO collection [, ...]
[USING {[bind_type] bind_argument} [, ...]] ;パラメーター:
| パラメーター | 説明 |
|---|---|
sql_expression | 実行する動的 SQL 文字列 |
collection | 対象コレクション。単一コレクションは単一フィールドまたは RecordType を保持できる。複数コレクションの場合は、それぞれが単一フィールドを保持する必要がある |
bind_type | バインド引数の方向(下記の表を参照) |
bind_argument | sql_expression に値を渡す、または sql_expression |
バインドタイプの値:
| バインドタイプ | 方向 | 説明 |
|---|---|---|
IN | 入力 | bind_argument の値を sql_expression |
OUT | 出力 | sql_expression によって返された値を bind_argument |
IN OUT | 双方向 | bind_argument を sql_expression に渡し、その後返された値を再び bind_argument |
RETURNING INTO 句と BULK COLLECT
DELETE、INSERT、または UPDATE 文の RETURNING INTO 句に BULK COLLECT を追加すると、別途クエリを実行せずに影響を受けた行をコレクションにキャプチャできます。基本となる各文の詳細については、INSERT、UPDATE、および DELETE をご参照ください。
構文:
{ insert | update | delete }
RETURNING { * | expr_1 [, expr_2 ] ...}
BULK COLLECT INTO collection [, ...] ;コレクションのルール:
単一コレクションは単一フィールドまたは RecordType を保持できます。
複数コレクションの場合は、それぞれが単一フィールドを保持する必要があります。
RETURNING キーワード後の式は、対象となるすべてのコレクションと、個数・順序・型の互換性において一致している必要があります。
* を使用してすべての列を返す機能は、PolarDB for PostgreSQL (Compatible with Oracle) の拡張であり、Oracle データベースとの互換性はありません。例
以下の例では、emp テーブルから CLERK ロールの従業員をコピーして作成した clerkemp テーブルを使用します。
CREATE TABLE clerkemp AS SELECT * FROM emp WHERE job = 'CLERK';
SELECT * FROM clerkemp; empno | ename | job | mgr | hiredate | sal | comm | deptno
-------+--------+-------+------+--------------------+---------+------+--------
7369 | SMITH | CLERK | 7902 | 17-DEC-80 00:00:00 | 800.00 | | 20
7876 | ADAMS | CLERK | 7788 | 23-MAY-87 00:00:00 | 1100.00 | | 20
7900 | JAMES | CLERK | 7698 | 03-DEC-81 00:00:00 | 950.00 | | 30
7934 | MILLER | CLERK | 7782 | 23-JAN-82 00:00:00 | 1300.00 | | 10
(4 rows)例 1:複数の単一フィールドコレクションへの UPDATE RETURNING
この例では、すべての給与を 1.5 倍に引き上げ、更新後の従業員番号、氏名、給与を 3 つの別々の連想配列にキャプチャします。
DECLARE
TYPE empno_tbl IS TABLE OF emp.empno%TYPE INDEX BY BINARY_INTEGER;
TYPE ename_tbl IS TABLE OF emp.ename%TYPE INDEX BY BINARY_INTEGER;
TYPE sal_tbl IS TABLE OF emp.sal%TYPE INDEX BY BINARY_INTEGER;
t_empno EMPNO_TBL;
t_ename ENAME_TBL;
t_sal SAL_TBL;
BEGIN
UPDATE clerkemp SET sal = sal * 1.5 RETURNING empno, ename, sal
BULK COLLECT INTO t_empno, t_ename, t_sal;
DBMS_OUTPUT.PUT_LINE('EMPNO ENAME SAL ');
DBMS_OUTPUT.PUT_LINE('----- ------- -------- ');
FOR i IN 1..t_empno.COUNT LOOP
DBMS_OUTPUT.PUT_LINE(t_empno(i) || ' ' || RPAD(t_ename(i),8) ||
' ' || TO_CHAR(t_sal(i),'99,999.99'));
END LOOP;
END;出力:
EMPNO ENAME SAL
----- ------- --------
7369 SMITH 1,200.00
7876 ADAMS 1,650.00
7900 JAMES 1,425.00
7934 MILLER 1,950.00例 2:単一 RecordType コレクションへの UPDATE RETURNING
この例では、RecordType で定義された単一コレクションを使用して、同じ結果を実現します。
DECLARE
TYPE emp_rec IS RECORD (
empno emp.empno%TYPE,
ename emp.ename%TYPE,
sal emp.sal%TYPE
);
TYPE emp_tbl IS TABLE OF emp_rec INDEX BY BINARY_INTEGER;
t_emp EMP_TBL;
BEGIN
UPDATE clerkemp SET sal = sal * 1.5 RETURNING empno, ename, sal
BULK COLLECT INTO t_emp;
DBMS_OUTPUT.PUT_LINE('EMPNO ENAME SAL ');
DBMS_OUTPUT.PUT_LINE('----- ------- -------- ');
FOR i IN 1..t_emp.COUNT LOOP
DBMS_OUTPUT.PUT_LINE(t_emp(i).empno || ' ' ||
RPAD(t_emp(i).ename,8) || ' ' ||
TO_CHAR(t_emp(i).sal,'99,999.99'));
END LOOP;
END;出力:
EMPNO ENAME SAL
----- ------- --------
7369 SMITH 1,200.00
7876 ADAMS 1,650.00
7900 JAMES 1,425.00
7934 MILLER 1,950.00例 3:RecordType コレクションへの DELETE RETURNING
この例では、clerkemp テーブルのすべての行を削除し、削除された行を表示用の連想配列にキャプチャします。
DECLARE
TYPE emp_rec IS RECORD (
empno emp.empno%TYPE,
ename emp.ename%TYPE,
job emp.job%TYPE,
hiredate emp.hiredate%TYPE,
sal emp.sal%TYPE,
comm emp.comm%TYPE,
deptno emp.deptno%TYPE
);
TYPE emp_tbl IS TABLE OF emp_rec INDEX BY BINARY_INTEGER;
r_emp EMP_TBL;
BEGIN
DELETE FROM clerkemp RETURNING empno, ename, job, hiredate, sal,
comm, deptno BULK COLLECT INTO r_emp;
DBMS_OUTPUT.PUT_LINE('EMPNO ENAME JOB HIREDATE ' ||
'SAL ' || 'COMM DEPTNO');
DBMS_OUTPUT.PUT_LINE('----- ------- --------- --------- ' ||
'-------- ' || '-------- ------');
FOR i IN 1..r_emp.COUNT LOOP
DBMS_OUTPUT.PUT_LINE(r_emp(i).empno || ' ' ||
RPAD(r_emp(i).ename,8) || ' ' ||
RPAD(r_emp(i).job,10) || ' ' ||
TO_CHAR(r_emp(i).hiredate,'DD-MON-YY') || ' ' ||
TO_CHAR(r_emp(i).sal,'99,999.99') || ' ' ||
TO_CHAR(NVL(r_emp(i).comm,0),'99,999.99') || ' ' ||
r_emp(i).deptno);
END LOOP;
END;出力:
EMPNO ENAME JOB HIREDATE SAL COMM DEPTNO
----- ------- --------- --------- -------- -------- ------
7369 SMITH CLERK 17-DEC-80 1,200.00 .00 20
7876 ADAMS CLERK 23-MAY-87 1,650.00 .00 20
7900 JAMES CLERK 03-DEC-81 1,425.00 .00 30
7934 MILLER CLERK 23-JAN-82 1,950.00 .00 10