Top > PLSQL プログラミング入門(1) > カーソル・ループ処理

明示カーソルと暗黙カーソル

カーソル(CURSOR) とは、主に問い合わせ(データ操作も含む)を行なうための情報を管理する作業領域をあらわすための「タグ」のようなものである。 このカーソルにユーザーが名前を付けているものを 明示カーソル と呼ぶ。 暗黙カーソル では Oracle によって用意されている名前の無い作業領域を使用している。

明示カーソルを使用するとカーソルの再利用や %ROWTYPE などを使用してメタデータ(定義情報)を PL/SQL 上などから容易にフェッチ(取り出し)することができる。

暗黙カーソルを使用した SELECT 文による FOR ループ

カーソルを使用せずに FOR の制御リストに記述することでループ変数に結果レコードを代入する。
SELECT した結果セットが存在しない場合にはループ処理は発生しない。

SQLPlus の場合には実行の前に SET SERVEROUTPUT ON を実行しておく。

CREATE OR REPLACE PROCEDURE RIVUS.STEP01_SELECT1
IS
BEGIN
	FOR vRec IN (
		SELECT 'data1' COLNAME_1 FROM DUAL
		UNION ALL SELECT 'data2' COLNAME_1 FROM DUAL
	) LOOP
		-- 暗黙カーソルの各属性は使用できない。
		DBMS_OUTPUT.PUT(NVL(TO_CHAR(SQL%ROWCOUNT),'NULL') || ':');
		DBMS_OUTPUT.PUT_LINE(vRec.COLNAME_1);
	END LOOP;
END;
/
--
-- 実行結果
SQL> call step01_select1();
NULL:data1
NULL:data2
 
コールが完了しました。

注意:Oracle 10g 現在、暗黙カーソルを使用した FOR ループには 暗黙カーソルの SQL 属性を使用することができない。

明示カーソルを使用した SELECT 文による FOR ループ

暗黙カーソルの例の内容に加えて、プロシージャのパラメータを直接埋め込み、カーソルの引数をデフォルト値指定ありで宣言している(カーソルを使用するときに引数が無くても良い)。

CREATE OR REPLACE PROCEDURE RIVUS.STEP01_SELECT2(P_DATA_1 IN VARCHAR2)
IS
	CURSOR cDual(P_DATA_2 VARCHAR2 := 'CURSOR param') IS
		SELECT P_DATA_1 COLNAME_1 FROM DUAL
		UNION ALL SELECT P_DATA_2 COLNAME_1 FROM DUAL ;
BEGIN
	FOR vRec IN cDual('xxx') LOOP
		DBMS_OUTPUT.PUT(cDual%ROWCOUNT || ':');
		DBMS_OUTPUT.PUT_LINE(vRec.COLNAME_1);
	END LOOP;
END;
/
--
-- 実行結果
SQL> call step01_select2('SELECT2');
1:SELECT2
2:xxx
 
コールが完了しました。

注意: フェッチする前にレコード件数を知るための手段として ROWCOUNT 属性は使用できない。

SELECT の場合にはカーソルの ROWCOUNT 属性は SELECT において取り出した件数をカウントする。そのため検索に一致する結果セットの件数と一致するのは、すべてのフェッチが終了したときである。

明示的なカーソルのオープンとフェッチ処理

上記の例は FOR ループ処理の内部で カーソルのオープンとフェッチ処理が行なわれていたが、それを明示的に行なうループ処理を記述してみる。

CREATE OR REPLACE PROCEDURE RIVUS.STEP01_SELECT3(P_DATA_1 IN VARCHAR2)
IS
	CURSOR cDual(P_DATA_2 VARCHAR2 := 'CURSOR param') IS
		SELECT P_DATA_1 COLNAME_1 FROM DUAL
	        UNION ALL SELECT P_DATA_2 COLNAME_1 FROM DUAL ;
	vRec	cDual%ROWTYPE;
BEGIN
	OPEN cDual('yyy') ;  -- 引数付きのカーソルをオープン
	LOOP
		FETCH cDual INTO vRec; -- カーソルの内容をフェッチする
		EXIT WHEN cDual%NOTFOUND;
		DBMS_OUTPUT.PUT(cDual%ROWCOUNT || ':');
		DBMS_OUTPUT.PUT_LINE(vRec.COLNAME_1);
	END LOOP;
	CLOSE cDual; -- 使用済のカーソルは必ずクローズすること
END;
/
--
-- 実行結果
SQL> call step01_select3('SELECT3');
1:SELECT3
2:yyy
 
コールが完了しました。


カーソル処理 関連事項

日本オラクル
■ 日本オラクル 株式会社
■ オラクルマスター資格 (オラクルマスターとは
■ Oracle のライセンスがわからない…
Oracle Direct (ネットで聞いても最後はここで要確認)