6.4 カーソル変数
カーソル変数は、明示カーソルと似ていますが、次の点が異なります。
-
1つの問合せに限定されません。
カーソル変数を問合せに対してオープンし、結果セットを処理した後、カーソル変数を別の問合せのために使用できます。
-
値を代入できます。
-
式で使用できます。
-
サブプログラム・パラメータとして使用できます。
カーソル変数は、サブプログラム間で問合せ結果セットを渡すために使用できます。
-
ホスト変数として使用できます。
カーソル変数は、PL/SQLのストアド・サブプログラムとそれらのクライアントとの間で問合せ結果セットを渡すために使用できます。
-
パラメータを受け入れることはできません。
カーソル変数にパラメータを渡すことはできませんが、問合せ全体を渡すことができます。問合せには変数を組み込むことができます。
カーソル変数がこのような柔軟性を持つ理由は、それがポインタであるため(その値が項目自体ではなく項目のアドレスを示すため)です。
カーソル変数を参照する前に、カーソル変数をオープンするか、オープンされたPL/SQLカーソル変数またはホスト・カーソル変数の値をカーソル変数に代入することで、SQL作業領域を指すようにする必要があります。
ノート:
カーソル変数と明示カーソルには互換性がありません(一方の値が期待されている場所で、もう一方は使用できません)。たとえば、カーソルFOR LOOP文の中ではカーソル変数を参照できません。
ここでのトピック
関連項目:
-
明示カーソルの詳細は、「明示カーソル」を参照してください
-
カーソル変数のその他のメリットの詳細は、『Oracle Database開発ガイド』を参照してください
-
カーソル変数のデメリットの詳細は、『Oracle Database開発ガイド』を参照してください。
6.4.1 カーソル変数の作成
カーソル変数を作成するには、事前定義のSYS_REFCURSOR型の変数を宣言するか、REF CURSOR型を定義してからその型の変数を宣言します。
ノート:
カーソル変数は、通称でREF CURSORと呼ばれることがあります。
REF CURSOR型の定義の基本構文は、次のとおりです。
TYPE type_name IS REF CURSOR [ RETURN return_type ]
構文およびセマンティクスの詳細は、「カーソル変数の宣言」を参照してください。
return_typeを指定する場合、REF CURSOR型とその型のカーソル変数は、強い型になりますが、指定しない場合、それらは弱い型になります。SYS_REFCURSORとその型のカーソル変数は、弱い型です。
強いカーソル変数には、指定した型を戻す問合せのみを関連付けることができます。弱いカーソル変数には、任意の問合せを関連付けることができます。
弱いカーソル変数は、強いカーソル変数よりエラーの発生する可能性が高まりますが、より柔軟な処理が可能です。弱いREF CURSOR型は、相互に互換性があり、事前定義のSYS_REFCURSOR型とも互換性があります。弱いカーソル変数の値は、他の弱いカーソル変数に代入できます。
強いカーソル変数の値を別の強いカーソル変数に代入できるのは、(戻り型が同じである以外に)両方のカーソル変数の型が同じである場合のみです。
ノート:
テーブル・ファンクションの弱いカーソル変数引数をパーティション化するには、PARTITION BY RANGEやPARTITION BY HASHではなく、PARTITION BY ANY句のみを使用します。
構文およびセマンティクスの詳細は、PARALLEL_ENABLE句を参照してください。
例6-24 カーソル変数の宣言
この例では、強い型と弱い型のREF CURSOR、それらの型の変数、および事前定義のSYS_REFCURSOR型の変数を定義しています。
DECLARE TYPE empcurtyp IS REF CURSOR RETURN employees%ROWTYPE; -- strong type TYPE genericcurtyp IS REF CURSOR; -- weak type cursor1 empcurtyp; -- strong cursor variable cursor2 genericcurtyp; -- weak cursor variable my_cursor SYS_REFCURSOR; -- weak cursor variable TYPE deptcurtyp IS REF CURSOR RETURN departments%ROWTYPE; -- strong type dept_cv deptcurtyp; -- strong cursor variable BEGIN NULL; END; /
例6-25 ユーザー定義の戻り型を持つカーソル変数
この例では、EmpRecTypは、ユーザー定義のRECORD型です。
DECLARE TYPE EmpRecTyp IS RECORD ( employee_id NUMBER, last_name VARCHAR2(25), salary NUMBER(8,2)); TYPE EmpCurTyp IS REF CURSOR RETURN EmpRecTyp; emp_cv EmpCurTyp; BEGIN NULL; END; /
6.4.2 カーソル変数のオープンおよびクローズ
カーソル変数を宣言したら、OPEN FOR文でその変数をオープンし、次の操作を実行できます。
-
カーソル変数を問合せに関連付けます(通常、この問合せで複数の行が戻されます)。
問合せには、バインド変数用のプレースホルダを含め、その値を
OPENFOR文のUSING句で指定できます。 -
問合せを処理するデータベース・リソースを割り当てます。
-
次のように問合せを処理します。
-
結果セットを識別します。
問合せが変数を参照している場合、結果セットはそれらの値に影響を受けます。詳細は、「カーソル変数問合せの変数」を参照してください。
-
問合せに
FORUPDATE句がある場合、結果セットの行をロックします。詳細は、「SELECT FOR UPDATEカーソルとFOR UPDATEカーソル」を参照してください。
-
-
カーソルを結果セットの最初の行の前に配置します。
カーソル変数は、再オープンする(別のOPEN FOR文で使用する)前にクローズする必要はありません。カーソル変数を再オープンすると、前にその変数に関連付けられていた問合せは失われます。
カーソル変数が必要なくなったら、CLOSE文を使用してクローズすることで、そのリソースを再利用できます。カーソル変数のクローズ後は、その結果セットからレコードをフェッチしたり、その属性を参照することはできません。これらの操作が試行されると、PL/SQLは事前定義の例外INVALID_CURSORを呼び出します。
クローズしたカーソル変数は、再オープンできます。
関連項目:
-
「OPEN FOR文の構文およびセマンティクス」の詳細は、「OPEN FOR文」を参照してください
-
CLOSE文の構文およびセマンティクスの詳細は、「CLOSE文」を参照してください
6.4.3 カーソル変数によるデータのフェッチ
カーソル変数をオープンしたら、FETCH文を使用して、問合せ結果セットの行をフェッチできます。
カーソル変数の戻り型は、FETCH文のinto_clauseと互換性を持つ必要があります。カーソル変数が強い型の場合、PL/SQLはコンパイル時に互換性がないことを捕捉します。カーソル変数が弱い型の場合、PL/SQLは実行時に互換性がないことを捕捉し、最初のフェッチの前に事前定義の例外ROWTYPE_MISMATCHを呼び出します。
関連項目:
-
FETCH文の構文およびセマンティクスの詳細は、「FETCH文」を参照してください
-
一度に複数の行を戻す
FETCH文の詳細は、「BULK COLLECT句を使用したFETCH文」を参照してください
例6-26 カーソル変数によるデータのフェッチ
この例では、例6-6で2つの明示カーソルを使用して処理していたことを、1つのカーソル変数を使用して処理しています。最初のOPEN FOR文には、問合せ自体が含まれます。2番目のOPEN FOR文は、その値が問合せである変数を参照します。
DECLARE cv SYS_REFCURSOR; -- cursor variable v_lastname employees.last_name%TYPE; -- variable for last_name v_jobid employees.job_id%TYPE; -- variable for job_id query_2 VARCHAR2(200) := 'SELECT * FROM employees WHERE REGEXP_LIKE (job_id, ''[ACADFIMKSA]_M[ANGR]'') ORDER BY job_id'; v_employees employees%ROWTYPE; -- record variable row of table BEGIN OPEN cv FOR SELECT last_name, job_id FROM employees WHERE REGEXP_LIKE (job_id, 'S[HT]_CLERK') ORDER BY last_name; LOOP -- Fetches 2 columns into variables FETCH cv INTO v_lastname, v_jobid; EXIT WHEN cv%NOTFOUND; DBMS_OUTPUT.PUT_LINE( RPAD(v_lastname, 25, ' ') || v_jobid ); END LOOP; DBMS_OUTPUT.PUT_LINE( '-------------------------------------' ); OPEN cv FOR query_2; LOOP -- Fetches entire row into the v_employees record FETCH cv INTO v_employees; EXIT WHEN cv%NOTFOUND; DBMS_OUTPUT.PUT_LINE( RPAD(v_employees.last_name, 25, ' ') || v_employees.job_id ); END LOOP; CLOSE cv; END; /
結果:
Atkinson ST_CLERK Bell SH_CLERK Bissot ST_CLERK ... Walsh SH_CLERK ------------------------------------- Higgins AC_MGR Greenberg FI_MGR Hartstein MK_MAN ... Zlotkey SA_MAN
例6-27 カーソル変数からコレクションへのフェッチ
この例では、FETCH文のBULK COLLECT句を使用して、カーソル変数から2つのコレクション(ネストした表)にフェッチします。
DECLARE
TYPE empcurtyp IS REF CURSOR;
TYPE namelist IS TABLE OF employees.last_name%TYPE;
TYPE sallist IS TABLE OF employees.salary%TYPE;
emp_cv empcurtyp;
names namelist;
sals sallist;
BEGIN
OPEN emp_cv FOR
SELECT last_name, salary FROM employees
WHERE job_id = 'SA_REP'
ORDER BY salary DESC;
FETCH emp_cv BULK COLLECT INTO names, sals;
CLOSE emp_cv;
-- loop through the names and sals collections
FOR i IN names.FIRST .. names.LAST
LOOP
DBMS_OUTPUT.PUT_LINE
('Name = ' || names(i) || ', salary = ' || sals(i));
END LOOP;
END;
/
結果:
Name = Ozer, salary = 11500 Name = Abel, salary = 11000 Name = Vishney, salary = 10500 ... Name = Kumar, salary = 6100
6.4.4 カーソル変数への値の代入
PL/SQLカーソル変数に、別のPL/SQLカーソル変数またはホスト・カーソル変数の値を代入できます。
構文は次のとおりです:
target_cursor_variable := source_cursor_variable;
source_cursor_variableがオープンしている場合、代入後にtarget_cursor_variableもオープンします。2つのカーソル変数は、同じSQL作業領域を指します。
source_cursor_variableがオープンしていない場合、代入後にtarget_cursor_variableがオープンしても、source_cursor_variableはオープンしません。
6.4.5 カーソル変数問合せの変数
カーソル変数に関連付けられた問合せでは、有効範囲内にある任意の変数を参照できます。
OPEN FOR文を使用してカーソル変数をオープンすると、PL/SQLによって問合せ内のすべての変数が評価され、結果セットの識別時にそれらの値が使用されます。変数の値を後で変更しても、結果セットは変更されません。
結果セットを変更するには、例6-29に示すとおり、変数の値を変更してから同じ問合せでカーソル変数を再度オープンする必要があります。
例6-28 カーソル変数問合せの変数(結果セットの変更なし)
この例では、値2を持つ変数factorを参照する問合せのカーソル変数をオープンしています。したがって、sal_multipleは、各フェッチ後にfactorが増分されても、常にsalの2倍になります。
DECLARE sal employees.salary%TYPE; sal_multiple employees.salary%TYPE; factor INTEGER := 2; cv SYS_REFCURSOR; BEGIN OPEN cv FOR SELECT salary, salary*factor FROM employees WHERE job_id LIKE 'AD_%'; -- PL/SQL evaluates factor LOOP FETCH cv INTO sal, sal_multiple; EXIT WHEN cv%NOTFOUND; DBMS_OUTPUT.PUT_LINE('factor = ' || factor); DBMS_OUTPUT.PUT_LINE('sal = ' || sal); DBMS_OUTPUT.PUT_LINE('sal_multiple = ' || sal_multiple); factor := factor + 1; -- Does not affect sal_multiple END LOOP; CLOSE cv; END; /
結果:
factor = 2 sal = 4400 sal_multiple = 8800 factor = 3 sal = 24000 sal_multiple = 48000 factor = 4 sal = 17000 sal_multiple = 34000 factor = 5 sal = 17000 sal_multiple = 34000
例6-29 カーソル変数問合せの変数(結果セットの変更あり)
DECLARE sal employees.salary%TYPE; sal_multiple employees.salary%TYPE; factor INTEGER := 2; cv SYS_REFCURSOR; BEGIN DBMS_OUTPUT.PUT_LINE('factor = ' || factor); OPEN cv FOR SELECT salary, salary*factor FROM employees WHERE job_id LIKE 'AD_%'; -- PL/SQL evaluates factor LOOP FETCH cv INTO sal, sal_multiple; EXIT WHEN cv%NOTFOUND; DBMS_OUTPUT.PUT_LINE('sal = ' || sal); DBMS_OUTPUT.PUT_LINE('sal_multiple = ' || sal_multiple); END LOOP; factor := factor + 1; DBMS_OUTPUT.PUT_LINE('factor = ' || factor); OPEN cv FOR SELECT salary, salary*factor FROM employees WHERE job_id LIKE 'AD_%'; -- PL/SQL evaluates factor LOOP FETCH cv INTO sal, sal_multiple; EXIT WHEN cv%NOTFOUND; DBMS_OUTPUT.PUT_LINE('sal = ' || sal); DBMS_OUTPUT.PUT_LINE('sal_multiple = ' || sal_multiple); END LOOP; CLOSE cv; END; /
結果:
factor = 2 sal = 4400 sal_multiple = 8800 sal = 24000 sal_multiple = 48000 sal = 17000 sal_multiple = 34000 sal = 17000 sal_multiple = 34000 factor = 3 sal = 4400 sal_multiple = 13200 sal = 24000 sal_multiple = 72000 sal = 17000 sal_multiple = 51000 sal = 17000 sal_multiple = 51000
6.4.6 コレクションの問合せ
次のすべてが該当する場合、コレクションを問い合せることができます。
-
コレクションのデータ型が、スキーマ・レベルで作成されているか、またはパッケージ仕様部で宣言されている。
-
コレクション要素のデータ型が、スカラー・データ型、ユーザー定義のデータ型またはレコード型のいずれかである。
問合せのFROM句では、コレクションはtable_collection_expressionにTABLE演算子の引数として指定されます。
ノート:
SQLコンテキストでは、戻り型がパッケージ仕様部で宣言されているファンクションを使用できません。
関連項目:
-
table_collection_expressionの詳細は、『Oracle Database SQL言語リファレンス』を参照してください -
CREATEPACKAGE文の詳細は、「CREATE PACKAGE文」を参照してください -
コレクション型およびコレクション変数の詳細は、「PL/SQLのコレクションおよびレコード」を参照してください
-
例7-9、システム固有の動的SQLを使用したコレクションの問合せ
例6-30 静的SQLを使用したコレクションの問合せ
この例では、カーソル変数がレコードの連想配列の問合せに関連付けられています。ネストした表型mytabは、パッケージ仕様部で宣言されています。
CREATE OR REPLACE PACKAGE pkg AUTHID DEFINER AS TYPE rec IS RECORD(f1 NUMBER, f2 VARCHAR2(30)); TYPE mytab IS TABLE OF rec INDEX BY pls_integer; END; DECLARE v1 pkg.mytab; -- collection of records v2 pkg.rec; c1 SYS_REFCURSOR; BEGIN v1(1).f1 := 1; v1(1).f2 := 'one'; OPEN c1 FOR SELECT * FROM TABLE(v1); FETCH c1 INTO v2; CLOSE c1; DBMS_OUTPUT.PUT_LINE('Values in record are ' || v2.f1 || ' and ' || v2.f2); END; /
結果:
Values in record are 1 and one
6.4.7 カーソル変数の属性
カーソル変数は明示カーソルと同じ属性を持ちます(「明示カーソル属性」を参照)。カーソル変数の属性値の構文は、cursor_variable_nameのすぐ後にattributeが続きます(たとえば、cv%ISOPEN)。カーソル変数をオープンしていない場合、%ISOPEN以外の属性を参照すると、事前定義の例外INVALID_CURSORが呼び出されます。
6.4.8 サブプログラム・パラメータとしてのカーソル変数
カーソル変数は、サブプログラム・パラメータとして使用することができ、この使用方法は、サブプログラム間で問合せ結果を渡す場合に便利です。
たとえば:
-
カーソル変数をあるサブプログラムでオープンし、別のサブプログラムで処理できます。
-
多言語アプリケーションでは、PL/SQLサブプログラムは、カーソル変数を使用して、異なる言語で記述されたサブプログラムに結果セットを戻すことができます。
ノート:
起動元と起動先のサブプログラムは、同じデータベース・インスタンス内に存在する必要があります。データベース・リンクを介して起動されたサブプログラムに、カーソル変数を渡したり、戻すことはできません。
注意:
カーソル変数はポインタであるため、カーソル変数をサブプログラム・パラメータとして使用すると、サブプログラム・パラメータのエイリアシングの可能性が高くなり、意図しない結果が発生することがあります。詳細は、「カーソル変数パラメータによるサブプログラムのパラメータのエイリアシング」を参照してください。
カーソル変数をサブプログラムの仮パラメータとして宣言する場合、次のことに注意してください。
-
サブプログラムがカーソル変数をオープンするか、カーソル変数に値を代入する場合、パラメータ・モードは
INOUTである必要があります。 -
サブプログラムがカーソル変数からフェッチするか、カーソル変数をクローズするのみである場合、パラメータ・モードは
INまたはINOUTのどちらでも可能です。
対応するカーソル変数の仮パラメータと実パラメータの戻り型には、互換性が必要です。それ以外の場合、PL/SQLは事前定義の例外ROWTYPE_MISMATCHを呼び出します。
異なるPL/SQLユニットのサブプログラム間でカーソル変数パラメータを渡すには、パッケージでパラメータのREF CURSOR型を定義します。型がパッケージに含まれる場合、複数のサブプログラムでその型を使用できます。あるサブプログラムでその型の仮パラメータを宣言し、別のサブプログラムでその型の変数を宣言して、それらの変数を最初のサブプログラムに渡すことができます。
関連項目:
-
サブプログラムのパラメータの詳細は、「サブプログラムのパラメータ」を参照してください
-
仮カーソル変数パラメータで実パラメータとして使用できる
CURSOR式の詳細は、「CURSOR式」を参照してください -
パッケージの詳細は、「PL/SQLパッケージ」を参照してください
例6-31 1つの問合せ用にカーソル変数をオープンするプロシージャ
この例では、REF CURSOR型と、その型のカーソル変数パラメータをオープンするプロシージャをパッケージで定義しています。
CREATE OR REPLACE PACKAGE emp_data AUTHID DEFINER AS TYPE empcurtyp IS REF CURSOR RETURN employees%ROWTYPE; PROCEDURE open_emp_cv (emp_cv IN OUT empcurtyp); END emp_data; / CREATE OR REPLACE PACKAGE BODY emp_data AS PROCEDURE open_emp_cv (emp_cv IN OUT EmpCurTyp) IS BEGIN OPEN emp_cv FOR SELECT * FROM employees; END open_emp_cv; END emp_data; /
例6-32 選択された問合せ用のカーソル変数のオープン(同じ戻り型)
この例では、ストアド・プロシージャが選択された問合せ用にカーソル変数パラメータをオープンします。問合せには、同じ戻り型が含まれます。
CREATE OR REPLACE PACKAGE emp_data AUTHID DEFINER AS TYPE empcurtyp IS REF CURSOR RETURN employees%ROWTYPE; PROCEDURE open_emp_cv (emp_cv IN OUT empcurtyp, choice INT); END emp_data; / CREATE OR REPLACE PACKAGE BODY emp_data AS PROCEDURE open_emp_cv (emp_cv IN OUT empcurtyp, choice INT) IS BEGIN IF choice = 1 THEN OPEN emp_cv FOR SELECT * FROM employees WHERE commission_pct IS NOT NULL; ELSIF choice = 2 THEN OPEN emp_cv FOR SELECT * FROM employees WHERE salary > 2500; ELSIF choice = 3 THEN OPEN emp_cv FOR SELECT * FROM employees WHERE department_id = 100; END IF; END; END emp_data; /
例6-33 選択された問合せ用のカーソル変数のオープン(異なる戻り型)
この例では、ストアド・プロシージャが選択された問合せ用にカーソル変数パラメータをオープンします。問合せには、異なる戻り型が含まれます。
CREATE OR REPLACE PACKAGE admin_data AUTHID DEFINER AS TYPE gencurtyp IS REF CURSOR; PROCEDURE open_cv (generic_cv IN OUT gencurtyp, choice INT); END admin_data; / CREATE OR REPLACE PACKAGE BODY admin_data AS PROCEDURE open_cv (generic_cv IN OUT gencurtyp, choice INT) IS BEGIN IF choice = 1 THEN OPEN generic_cv FOR SELECT * FROM employees; ELSIF choice = 2 THEN OPEN generic_cv FOR SELECT * FROM departments; ELSIF choice = 3 THEN OPEN generic_cv FOR SELECT * FROM jobs; END IF; END; END admin_data; /
6.4.9 ホスト変数としてのカーソル変数
カーソル変数は、ホスト変数として使用することができ、この使用方法は、PL/SQLのストアド・サブプログラムとそれらのクライアントとの間で問合せ結果を渡す場合に便利です。
カーソル変数がホスト変数の場合、PL/SQLとクライアント(ホスト環境)は、結果セットを格納するSQL作業領域に対するポインタを共有します。
カーソル変数をホスト変数として使用するには、ホスト環境内でカーソル変数を宣言し、その変数を入力ホスト変数(バインド変数)としてPL/SQLに渡します。ホスト・カーソル変数は、(弱いPL/SQLカーソル変数と同様に)すべての問合せの戻り型と互換性があります。
カーソル変数の値を1つの有効範囲から別の有効範囲に渡したとしても、SQL作業領域は、それを指すカーソル変数が存在するかぎりアクセス可能です。たとえば、例6-34で、Pro*Cプログラムはホスト・カーソル変数を埋込みPL/SQL無名ブロックに渡しています。ブロックの実行後も、カーソル変数はSQL作業領域を指しています。
クライアント側にPL/SQLエンジンがあれば、クライアントからサーバーへのコールに課される制限はありません。たとえば、クライアント側でカーソル変数を宣言し、それをサーバー側でオープンしてフェッチした後で、クライアント側で引き続きフェッチすることができます。また、複数のホスト・カーソル変数を1回の往復でオープンまたはクローズするPL/SQL無名ブロックを使用することで、ネットワークの通信量を削減できます。たとえば:
/* PL/SQL anonymous block in host environment */ BEGIN OPEN :emp_cv FOR SELECT * FROM employees; OPEN :dept_cv FOR SELECT * FROM departments; OPEN :loc_cv FOR SELECT * FROM locations; END; /
PL/SQL無名ブロックの実行後もカーソル変数はSQL作業領域を指しているため、クライアント・プログラムではそれらの作業領域を使用できます。クライアント・プログラムでカーソルが必要なくなった場合、PL/SQL無名ブロックを使用してそれらのカーソルをクローズできます。たとえば:
/* PL/SQL anonymous block in host environment */ BEGIN CLOSE :emp_cv; CLOSE :dept_cv; CLOSE :loc_cv; END; /
この方法は、Oracle Formsと同様に、マルチブロック・フォームにデータを移入する場合に便利です。たとえば、次のように1回の往復で複数のSQL作業領域をオープンできます。
/* PL/SQL anonymous block in host environment */ BEGIN OPEN :c1 FOR SELECT 1 FROM DUAL; OPEN :c2 FOR SELECT 1 FROM DUAL; OPEN :c3 FOR SELECT 1 FROM DUAL; END; /
ノート:
ホスト・カーソル変数をOracle Call Interface(OCI)クライアントからPL/SQLにバインドすると、同じサーバー・コールで変数をオープンしないかぎり、サーバー側の変数からフェッチすることはできません。
例6-34 Pro*Cクライアント・プログラムにおけるホスト変数としてのカーソル変数
この例では、Pro*Cクライアント・プログラムでカーソル変数と選択子を宣言し、それらをホスト変数としてPL/SQL無名ブロックに渡すことで、選択した問合せ用にカーソル変数をオープンしています。
EXEC SQL BEGIN DECLARE SECTION;
SQL_CURSOR generic_cv; -- Declare host cursor variable.
int choice; -- Declare selector.
EXEC SQL END DECLARE SECTION;
EXEC SQL ALLOCATE :generic_cv; -- Initialize host cursor variable.
-- Pass host cursor variable and selector to PL/SQL block.
/
EXEC SQL EXECUTE
BEGIN
IF :choice = 1 THEN
OPEN :generic_cv FOR SELECT * FROM employees;
ELSIF :choice = 2 THEN
OPEN :generic_cv FOR SELECT * FROM departments;
ELSIF :choice = 3 THEN
OPEN :generic_cv FOR SELECT * FROM jobs;
END IF;
END;
END-EXEC;