Tips5. CURSORでデータを取得するPL/SQLサンプルコード
ここではおなじみのemp表からデータを取得し、dbms_output.put_lineでコンソールに出力するというPL/SQLコードを、カーソルを使い分けてコーディングしてみました。
それぞれ特徴があります。
最近はサーバリソースに余裕が出てきたこともあるのか、4.BULK COLLECTを使用するケースが増えていると思います。
それぞれ特徴がありますので、その場その場の状況に応じて、使い分けましょう。
1. 最もスタンダードなOPEN~FETCHカーソルループ
最近はあまり使われることがないと思われる記述方法です。
ループ処理を細かく制御したい場合に使用します。
また、敢えてループせずにレコードを1件のみ取得したい場合に使用したりします。
DECLARE CURSOR c_emp(p_dno IN VARCHAR2) IS SELECT empno, ename FROM emp WHERE deptno = p_dno ; rec_emp c_emp%ROWTYPE; BEGIN OPEN c_emp('10'); LOOP FETCH c_emp INTO rec_emp; -- コーディングは面倒ですが細かな制御が可能 EXIT WHEN c_emp%NOTFOUND; -- データが取れなくなったらループを抜ける dbms_output.put_line(rec_emp.empno || ':' || rec_emp.ename); END LOOP; CLOSE c_emp; EXCEPTION WHEN OTHERS THEN IF c_emp%ISOPEN THEN CLOSE c_emp; -- 例外処理でカーソルクローズが必須! END IF; RAISE; END; /
2. 最も実用的なカーソルFORループ(明示カーソル)
少し前まではこの記述がスタンダードだったと思います。
明示的にカーソルを定義しつつも、カーソルクローズの制御が不要で実用的な記述方法です。
-- DECLARE CURSOR c_emp(p_dno IN VARCHAR2) IS SELECT empno, ename FROM emp WHERE deptno = p_dno ; rec_emp c_emp%ROWTYPE; BEGIN FOR rec_emp IN c_emp('10') -- 記述がシンプル。 LOOP dbms_output.put_line(rec_emp.empno || ':' || rec_emp.ename); END LOOP; -- クローズの必要も無い END; /
3. カーソルFORループ(暗黙カーソル)
FOR文中にSQLを記述します。暗黙カーソルになりますので、SQLが可変となる場合に使用します。列数が不定の場合に使用するのかもしれませんが、仕様がわかりづらくなると思いますので、極力避けたいところです(WHERE句が可変となる場合は暗黙カーソルでも対応可能です)。
-- DECLARE -- カーソルの定義は不要 BEGIN -- FOR文中にカーソルの定義を記述 FOR rec_emp IN ( -- SQLが宣言部にないので再利用性はありません SELECT empno, ename FROM emp WHERE deptno = '10') LOOP dbms_output.put_line(rec_emp.empno || ':' || rec_emp.ename); END LOOP; END; /
4. 性能を向上させるためにBULK COLLECTを使用
最近はこの記述がスタンダードかもしれません。DBへのアクセスが1回のみで全件メモリにデータが載ってくるので、性能面ではメリットがあります。
事前のレコード型・テーブル型変数の定義が少々手間なのがたまに傷です。
-- DECLARE TYPE emp_rtype IS RECORD ( -- レコード型の定義 empno emp.empno%TYPE, ename emp.ename%TYPE ); TYPE emp_ttype IS TABLE OF emp_rtype; -- テーブル型の定義 rec_emp emp_ttype; -- テーブル型変数の宣言 BEGIN SELECT empno, ename BULK COLLECT INTO rec_emp -- BULK COLLECTで一気に取込 FROM emp WHERE deptno = '10' ; FOR i IN 1..rec_emp.count -- テーブル型変数の件数分繰り返し LOOP dbms_output.put_line(rec_emp(i).empno || ':' || rec_emp(i).ename); END LOOP; END; /
上手く使い分けましょう。
ディスカッション
コメント一覧
まだ、コメントがありません