JavaでのREFカーソルの使用

REF CURSORは、 OPENステートメントによって返されるクエリ結果セットへのポインタを含むカーソル変数です。静的カーソルとは異なり、 REF CURSORは特定のクエリに関連付けられていません。異なるクエリを含むOPENステートメントを使用して、同じREF CURSOR変数を何度でも開くことができます。そのたびに、そのクエリに対して新しい結果セットが作成され、カーソル変数を介して利用可能になります。 REF CURSORは、あるプロシージャから別のプロシージャに結果セットを渡すこともREF CURSOR 。

Advanced Serverは、 strongly-typed weakly-typed REF CURSORsとweakly-typed REF CURSORsの両方の宣言をサポートしています。強く型付けされたカーソルは、予想される結果セットのshape (各列の型)を宣言する必要があります。厳密に型指定されたカーソルは、宣言された列を返すクエリでのみ使用できます。異なる形状の結果セットを返すクエリでカーソルを開くと、サーバーは例外をスローします。一方、弱い型指定のカーソルは、任意の形状の結果セットで機能します。

強く型付けされたREF CURSORを宣言するには:

TYPE <cursor_type_name> IS REF CURSOR RETURN <return_type>;

弱く型付けされたREF_CURSORを宣言するには:

name SYS_REFCURSOR;

.. raw:: latex

  \newpage

REF CURSORを使用してResultSetを取得する

リスト1.11-aに示すストアドプロシージャ( getEmpNames )は、サーバー上に2つのREF CURSORsを構築します。最初のREF CURSORにはempテーブルの委託された従業員のリストが含まれ、2番目のREF CURSORにはempテーブルの給与を受けた従業員のリストが含まれます。

リスト1.11-a

 CREATE OR REPLACE PROCEDURE getEmpNames
(
  commissioned IN OUT SYS_REFCURSOR ,
  salaried IN OUT SYS_REFCURSOR
)
IS
BEGIN
  OPEN commissioned FOR SELECT ename FROM emp WHERE comm is NOT NULL ;
  OPEN salaried FOR SELECT ename FROM emp WHERE comm is NULL ;
END ;

RefCursorSample()メソッド(リスト1.11-bを参照)はgetEmpName()ストアドプロシージャを呼び出し、2つのREF CURSOR変数のそれぞれに返された名前を表示します。

リスト1.11-b

public void RefCursorSample(Connection con)
{
  try
  {
    con.setAutoCommit(false);
    String commandText = "{call getEmpNames(?,?)}";
    CallableStatement stmt = con.prepareCall(commandText);
    stmt.setNull(1, Types.REF);
    stmt.registerOutParameter(1, Types.REF);
    stmt.setNull(2, Types.REF);
    stmt.registerOutParameter(2, Types.REF);

    stmt.execute();
    ResultSet commissioned = (ResultSet)stmt.getObject(1);
    System.out.println("Commissioned employees:");
    while(commissioned.next())
    {
      System.out.println(commissioned.getString(1));
    }

    ResultSet salaried = (ResultSet)stmt.getObject(2);
    System.out.println("Salaried employees:");
    while(salaried.next())
    {
      System.out.println(salaried.getString(1));
    }
  }
  catch(Exception err)
  {
    System.out.println("An error has occurred.");
    System.out.println("See full details below.");
    err.printStackTrace();
  }
}

CallableStatementは、各REF CURSOR ( commissionedおよびsalaried )を準備しREF CURSOR 。各カーソルは、ストアドプロシージャgetEmpNames() IN OUTパラメーターとして返されます。

String commandText = "{call getEmpNames(?,?)}";
CallableStatement stmt = con.prepareCall(commandText);

registerOutParameter()の呼び出しは、最初のREF CURSOR(委託)のパラメータータイプ(Types.REF)を登録します。

stmt.setNull(1, Types.REF);
stmt.registerOutParameter(1、Types.REF); 

registerOutParameter()への別の呼び出しは、2番目のREF CURSOR (salaried) Types.REF )の2番目のパラメータータイプ( Types.REF )を登録します。

stmt.setNull(2, Types.REF);
stmt.registerOutParameter(2, Types.REF);

stmt.execute()を呼び出すと、ステートメントが実行されます。

stmt.execute();

getObject()メソッドは、最初のパラメーターから値を取得し、結果をResultSetキャストします。次に、 RefCursorSampleがカーソルを反復処理し、委託された各従業員の名前を出力します。

ResultSet commissioned = (ResultSet)stmt.getObject(1);
while(commissioned.next())
{
  System.out.println(commissioned.getString(1));
}

同じゲッターメソッドが2番目のパラメーターからResultSetを取得し、 RefCursorExampleそのカーソルを反復処理して、 RefCursorExample各従業員の名前を出力します。

ResultSet salaried = (ResultSet)stmt.getObject(2);
while(salaried.next())
{
  System.out.println(salaried.getString(1));
}