e-learning、オラクル研修、LMS(学習管理システム)のiStudy

e-learning、オラクル研修、LMS(学習管理システム)のiStudy

第9回 「カーソルのオープン、フェッチ、クローズ」

2012.02.13

前回はサンプルプログラムの中の、カーソル宣言を中心に解説をしましたが、今回は実行部でのカーソル処理の記述を中心に解説をします。すなわち、「カーソルのオープン、フェッチ、クローズ」です。

サンプルプログラムは以下のとおりでした。部門番号を指定して、その社員の一覧を表示するものです。

▼▼▼ サンプルプログラムの内容  行番号は説明の便宜上のものです ▼▼▼▼
1 set serveroutput on
2 set verify off
3 DECLARE
4 /* 明示カーソルの宣言 */
5 CURSOR CUR_EMP IS
6 SELECT EMPNO, ENAME FROM EMP
7 WHERE DEPTNO = &部門番号;
8 /* レコード型変数の宣言 */
9 REC CUR_EMP%ROWTYPE;
10 BEGIN
11 /* カーソルをオープン */
12 OPEN CUR_EMP;
13 /* 1行ずつ取得しながら画面表示 */
14 LOOP
15 FETCH CUR_EMP INTO REC;
16 EXIT WHEN CUR_EMP%NOTFOUND;
17 DBMS_OUTPUT.PUT_LINE(REC.EMPNO || ' ' || REC.ENAME);
18 END LOOP;
19 /* カーソルをクローズ */
20 CLOSE CUR_EMP;
21 END;
22 /
23 set verify on
▲▲▲ ここまで ▲▲▲

これをファイル(例 test.sql)に書いて(ただし行番号は除く)SQL*PlusやSQL*Developerなどから実行できます。以下はSQL*Plusの場合です。

▼▼▼ ここから ▼▼▼
SQL> @test.sql
部門番号に値を入力してください: 20
7369 SMITH
7566 JONES
7788 SCOTT
7876 ADAMS
7902 FORD PL/SQLプロシージャが正常に完了しました。
▲▲▲ ここまで ▲▲▲

このように、部門番号(DEPTNO)を指定して社員表(EMP)を問い合わせて、該当する複数社員の社員番号(EMPNO)と社員名(ENAME)を画面表示するものです。

では、今回はこのサンプルプログラムを元に実行部での処理を中心に解説します。

実行部ではカーソル処理の最初のステップとしてカーソルをオープンします(サンプル12行目)。構文は以下の通りです。

OPEN カーソル名;

オープン処理で、カーソルの元になっているSELECT文が実行されます。そしてその結果の行の集合がメモリに用意されます。その行の集合を「結果セット」といいます。この結果セットから1行を取り出し変数に格納することができます。その処理をフェッチと言います(サンプル15行目)。フェッチを繰り返すことで、結果セットの先頭行から順番に行を取り出すことができます。以下はフェッチの構文です。

FETCH カーソル名 INTO レコード変数;

プログラムではフェッチして、その行レコードで何らかの処理をし、また次の行をフェッチして同じ処理をする・・・、ということを繰り返すのが普通ですから、フェッチ処理とその行レコード処理は繰り返し処理の範囲になります。繰り返し処理を記述する方法はいくつかありますが、一番簡単な方法は繰り返す範囲を「LOOP」と「END LOOP;」で囲む方法です。これを基本ループ構文といいます。サンプルプログラムも基本ループを使っています。(サンプル14-18行目)

カーソル処理に限らず、ループで非常に大事なことは無限ループにならないように配慮するということです。例えば、フェッチ処理の繰り返しにより、結果セットの最後の行を越えてフェッチしてもシステムエラーは発生しません。ということは、何かの条件で繰り返しから抜ける記述がない限り、最終行を超えてもいつまでもフェッチを繰り返すことになります。いわゆる無限ループです。仮に最終行を越えてフェッチしたときエラーになってくれれば、例外処理部に制御が移るので無限ループにならなくて済むのですが、実際はそうではありません。最終行を越えてフェッチしたときには自分で判断してループから自発的に抜ける必要があります。その記述は以下の通りです。(サンプル 16行目)

EXIT WHEN カーソル名%NOTFOUND;

この構文の意味は、「カーソル名%NOTFOUNDがTRUEであればループから抜けなさい」という意味です。ここで、「カーソル名%NOTFOUND」という記述はカーソルの属性のひとつであり、最終行を越えてフェッチしたとき、値がTRUEになります。つまり、この構文をループの中に置けば、フェッチして行がなかったとき、ループから抜けることができて、無限ループにならなくて済むわけです。

細かく説明すると、最後の行をフェッチした時点ではカーソル名%NOTFOUNDはTRUEではありません。さらにもう一回フェッチすると行がないことが認識できて、カーソル名%NOTFOUNDがTRUEになります。よって、「EXIT WHEN カーソル名%NOTFOUND;」はフェッチ処理の直後に記述することが普通です。

いずれにしろ、無限ループになってしまうと、アプリケーションが固まったようになってしまい、強制終了しなければいけません。ですから、無限ループには気をつけてください。

また全部の行のフェッチが終わっても、「結果セット」全体がまだメモリに残っています。フェッチは常に結果セットの次の行をフェッチする動きであり、フェッチ済みの以前の行に戻ってフェッチすることはできません。よってすべての行のフェッチが終わった後の結果セットは、無用の長物であり、速やかに開放して領域をメモリに戻してあげるべきです。それがいわゆるクローズ処理です(サンプル 20行目)。クローズ処理の構文は以下の通りです。

CLOSE カーソル名;

このクローズ処理で結果セットが開放され、カーソル処理はすべて完了します。

いかがですか?全体の流れが掴めましたね。これで、データベースから問い合わせて、その結果の行に対して1行づつプログラム処理をするやり方がイメージできると思います。

まとめると、以下の通りです。

DECLARE
カーソルの宣言(SELECT文)
レコード変数の宣言
BEGIN
OPEN カーソル;
LOOP
FETCH カーソル INTO レコード変数;
EXIT WHEN カーソル名%NOTFOUND;
レコード変数の1行を用いた何らかのプログラム処理
END LOOP;
CLOSE カーソル;
END;

簡単ですね。

それでは今回はここまでです。次回も、カーソル処理を話題にします。カーソルに関する周辺の技術や仕様について解説いたします。それではご期待ください。

先頭へ戻る