16 Oracleコレクションの操作
この章では、Java配列とそのデータにマップされるOracleコレクションにアクセスして操作するための、標準Java Database Connectivity(JDBC)に対するOracleの拡張機能について説明します。次の内容について説明します。
ノート:
Oracle Database 12cリリース1 (12.1)以降、oracle.sql.ARRAYクラスは非推奨となり、oracle.jdbc.OracleArrayインタフェースに置き換えられています。このインタフェースはoracle.jdbcパッケージに属します。標準互換性には(可能であれば)java.sqlパッケージの使用可能なメソッドを使用し、Oracle固有の拡張機能にはoracle.jdbcパッケージの使用可能なメソッドを使用することをお薦めします。oracle.jdbc.OracleArrayインタフェースの詳細は、MoSノート1364193.1を参照してください。
16.1 コレクションのためのOracle拡張機能
この項の内容は次のとおりです。
16.1.1 Oracleコレクションの概要
データベース内の変数配列(VARRAY)またはNESTED TABLEのいずれかであるOracleコレクションは、Javaでは配列にマップされます。JDBC 2.0配列は、JavaでOracleコレクションをインスタンス化するために使用されます。コレクションおよび配列という用語は、どちらも同じ意味で使用されることがあります。ただし、データベース側ではコレクション、JDBCアプリケーション側では配列のほうが適切です。
サポートされるのは、SQL型名を指定することでコレクションの型を記述できる、名前付きコレクションのみです。JDBCを使用すると、次のものに配列を使用できます。
-
SELECT句の列 -
INまたはOUTバインド変数 -
Oracleオブジェクトの属性
-
他の配列の要素
16.1.2 コレクションのインスタンス化に関する選択
アプリケーションでは、弱い型指定のoracle.sql.ARRAYクラスのインスタンスとして、または事前に作成した強い型指定のカスタムJavaクラスのインスタンスとしてコレクションをインスタンス化するオプションがあります。コレクションのために使用するカスタムJavaクラスは、カスタム・コレクション・クラスと呼びます。カスタム・コレクション・クラスは、Oracleのoracle.jdbc.OracleDataインタフェースを実装する必要があります。さらに、カスタム・クラスまたはコンパニオン・クラスは、oracle.jdbc.OracleDataFactoryを実装する必要があります。標準java.sql.SQLDataインタフェースは、SQLオブジェクト型のマッピング専用です。
oracle.sql.ARRAYクラスは、標準のjava.sql.Arrayインタフェースを実装します。
ARRAYクラスには、配列全体を取り出し、配列要素のサブセットを取り出し、配列要素のSQLベース型名を取り出すための機能があります。ただし、setterメソッドがないため、配列に書き込むことはできません。
カスタム・コレクション・クラスを使用すると、ARRAYクラスと同様に、配列のすべてまたは一部を取得して、SQLベース型名を取得できます。強い型指定により、実行時まで検出できない可能性のあるコーディング・エラーを、コンパイル時に発見できる利点もあります。
ノート:
VARRAYへのアクセスとNESTED TABLEへのアクセス間で、コード上の違いはありません。ARRAYクラス・メソッドは、VARRAYまたはNESTED TABLEに適用されているかどうかを判断し、適切なアクションを決定して応答します。
16.1.3 コレクションの作成
Oracleは名前付きコレクションのみをサポートしているため、特定のVARRAY型名またはNESTED TABLE型名を制限する必要があります。VARRAYとNESTED TABLEは、型自体ではなく型のカテゴリです。
次のSQL CREATE TYPE文を使用してコレクションを作成すると、コレクションにSQL型名が割り当てられます。
CREATE TYPE <sql_type_name> AS <datatype>;
VARRAYは、サイズ可変の配列です。順序付けられたデータ要素のセットを保持し、要素はすべて同じデータ型です。各要素は、索引を持ちますが、これはVARRAY.における要素の位置に対応する番号です。VARRAY内の要素数は、そのVARRAYのサイズを表します。VARRAY型を宣言する場合は、最大サイズを指定する必要があります。たとえば:
CREATE TYPE myNumType AS VARRAY(10) OF NUMBER;
この文では、10要素以下のNUMBER値を持つVARRAYが記述されたSQL型名として、myNumTypeが定義されています。
ネストした表は順序を設定していないデータ要素のセットで、すべて同じデータ型です。ネストした表はデータベースの別の表に格納されます。この表は単一の列を持ち、この列の型は組込み型またはオブジェクト型です。表がオブジェクト・タイプの場合、オブジェクト・タイプの各属性の列を持つ複数列の表として表示されることがあります。ネストした表は、次のようにして作成することができます。
CREATE TYPE myNumList AS TABLE OF integer;
この文は、INTEGER型のNESTED TABLEに使用される表タイプが定義されたSQL型名として、myNumListを指定しています。
16.1.4 マルチ・レベルのコレクション型の作成
JDBCにおいてマルチ・レベルのコレクション型を作成する最も一般的な方法は、java.sql.StatementクラスのexecuteメソッドにSQLのCREATE TYPE文を渡すことです。次のコードは、first_levelという1レベルのNESTED TABLEと、second_levelという2レベルのNESTED TABLEを作成します。
Connection conn = .... // make a database
// connection
Statement stmt = conn.createStatement(); // open a database
// cursor
stmt.execute("CREATE TYPE first_level AS TABLE OF NUMBER"); // create a nested
// table of number
stmt.execute("CREATE TYPE second_level AS TABLE OF first_level"); // create a
// two-levels nested table
... // other operations here
stmt.close(); // release the
// resource
conn.close(); // close the
// database connection
マルチ・レベルのコレクション型を作成すると、実表の列またはオブジェクト型の属性として使用できます。
ノート:
マルチ・レベルのコレクション型は、Oracle9i以降でのみ使用可能です。
16.2 コレクション機能の概要
結果セットまたはコール可能文によって配列インスタンス内のコレクション・データを取得し、プリペアド文またはコール可能文内のバインド変数として戻すことができます。
標準java.sql.Arrayインタフェースを実装するoracle.sql.ARRAYクラスは、Oracleコレクションのデータにアクセスし、更新するために必要な機能を提供します。
この項では、配列のgetterメソッドとsetterメソッドについて説明します。Java配列としてコレクションを取り出し、渡すには、次の結果セット、コール可能文およびプリペアド文メソッドを使用します。
ノート:
Oracle Database 12cリリース1 (12.1)以降、oracle.sql.ARRAYクラスは非推奨となり、oracle.jdbc.OracleArrayインタフェースに置き換えられています。このインタフェースはoracle.jdbcパッケージに属します。標準互換性には(可能であれば)java.sqlパッケージの使用可能なメソッドを使用し、Oracle固有の拡張機能にはoracle.jdbcパッケージの使用可能なメソッドを使用することをお薦めします。oracle.jdbc.OracleArrayインタフェースの詳細は、MoSノート1364193.1を参照してください。
結果セットおよびコール可能文のgetterメソッド
OracleResultSetインタフェースとOracleCallableStatementインタフェースは、出力パラメータとして、つまりoracle.sql.ARRAYインスタンスまたはjava.sql.ArrayインスタンスとしてARRAYオブジェクトを取り出すために、getARRAY()メソッドとgetArray()メソッドをサポートします。getObjectメソッドも使用できます。これらのメソッドは、入力としてString列名またはint列索引を取ります。
ノート:
Oracle JDBCドライバは、配列および構造の記述子をキャッシュします。これには多数のパフォーマンス上の利点がありますが、データベース内で配列型の基礎となる型定義を変更すると、その配列型のキャッシュされた記述子は古くなり、アプリケーションでSQLExceptionが通知されます。
プリペアド文およびコール可能文のsetterメソッド
OraclePreparedStatementクラスとOracleCallableStatementクラスは、更新されたARRAYオブジェクトをバインド変数として取ってデータベースに渡すsetARRAYメソッドとsetArrayメソッドをサポートします。setObjectメソッドも使用できます。これらのメソッドは、oracle.sql.ARRAYインスタンスまたはjava.sql.Arrayインスタンスに加えて、Stringパラメータ名またはintパラメータ索引を入力として取ります。
16.3 ARRAYパフォーマンス拡張要素メソッド
この項では、次の項目について説明します。
16.3.1 Javaプリミティブ型の配列としてのoracle.sql.ARRAY要素へのアクセスについて
oracle.sql.ARRAYクラスには、配列要素をJavaプリミティブ型として戻すメソッドが含まれています。これらのメソッドを使用すると、Datumインスタンスとしてコレクション要素にアクセスしてからDatumインスタンスをJavaプリミティブ型に変換する方法に比べ、より容易にコレクション要素にアクセスできます。
ノート:
oracle.sql.ARRAYクラスのこれらの特殊なメソッドは、数値コレクションに制限されます。
最初のシグネチャを使用している各メソッドは、コレクション要素をXXX[]の形式で戻します。ここで、XXXはJavaプリミティブ型です。第2のシグネチャを使用している各メソッドは、countによって指定される数の要素を含んでいて、indexの場所で開始されるコレクションのスライスを戻します。
16.3.2 ARRAY自動要素バッファリング
Oracle JDBCドライバには、ARRAYの内容のバッファリングを有効または無効にするためのパブリック・メソッドが用意されています。
oracle.sql.ARRAYクラスには、次のメソッドがあります。
-
setAutoBuffering -
getAutoBuffering
ARRAY要素にgetAttributesおよびgetArrayの各メソッドで複数回アクセスし、ARRAYデータがオーバーフローせずにJava仮想マシン(JVM)のメモリーに格納されると想定する場合は、JDBCアプリケーションで自動バッファリングを有効にすることをお薦めします。
ノート:
変換した要素をバッファリングすると、JDBCアプリケーションでは、大量のメモリーが消費されます。
自動バッファリングを有効にすると、oracle.sql.ARRAYオブジェクトでは、変換したすべての要素のローカルのコピーが保持されます。このデータが保持されるため、この情報に2回目にアクセスするときにはデータ・フォーマット変換処理を実行しなくて済みます。
16.3.3 ARRAY自動索引作成
配列を自動索引作成モードにすると、配列オブジェクトは配列要素へのアクセスを迅速に行うために索引表をメンテナンスします。
oracle.sql.ARRAYクラスには、自動配列索引作成をサポートする次のメソッドが含まれています。
-
setAutoIndexing(boolean) -
setAutoIndexing(boolean, int)
デフォルトでは、自動索引作成は有効にされていません。JDBCアプリケーションで、getArrayおよびgetResultSetの各メソッドを使用して配列要素のランダム・アクセスを実行する場合は、ARRAYオブジェクトの自動索引作成を有効にします。
16.4 配列の作成と使用方法
この項では、配列オブジェクトを作成する方法と、配列オブジェクトとしてコレクションを取り出し、渡す方法について説明します。内容は次のとおりです。
16.4.1 ARRAYオブジェクトの作成
ノート:
Oracle JDBCでは、java.sql.ConnectionインタフェースのJDBC 4.0のcreateArrayOfメソッドはサポートされていません。Oracleの配列型はすべて名前付きですが、このメソッドでは匿名の配列型のみが許容されています。かわりにOracle固有のメソッド、oracle.jdbc.OracleConnection.createARRAYを使用してください。
この項では、ARRAYオブジェクトを作成する方法について説明します。この項の内容は次のとおりです。
ARRAYオブジェクトの作成に関するステップ
Oracle Database 11gリリース1以降、oracle.jdbc.OracleConnectionインタフェースのcreateARRAYファクトリ・メソッドを使用して配列オブジェクトを作成することができます。配列を作成するファクトリ・メソッドは次のように定義されています。
public ARRAY createARRAY(java.lang.String typeName,java.lang.Object elements)throws SQLException
ここで、typeNameは、作成されたオブジェクトのSQL型の名前で、elementsは作成されたオブジェクトの要素です。
ノート:
コレクション型の名前は、要素の型名と同じではありません。たとえば:
CREATE TYPE person AS object(c1 NUMBER(5), c2 VARCHAR2(30));CREATE TYPE array_of_persons AS varray(10)OF person;
前述の文では、コレクション型の名前は、ARRAY_OF_PERSONです。コレクション要素のSQL型名は、PERSONです。
例16-1 マルチ・レベル・コレクションの作成
JDBCアプリケーションは、シングル・レベル・コレクションと同様、oracle.sql.ARRAYインスタンスを作成してマルチ・レベル・コレクションを表し、インスタンスをデータベースに送信することができます。シングル・レベル・コレクションを作成するために使用するのと同じcreateARRAYファクトリ・メソッドを使用することによってマルチ・レベル・コレクションを作成することもできます。シングル・レベル・コレクションを作成する場合、要素は一次元のJava配列ですが、マルチ・レベル・コレクションを作成する場合、要素はoracle.sql.ARRAY[]要素の配列、ネストJava配列、またはその組合せです。
次のコードは、ネストしたJava配列を使用してコレクション型を作成する方法を示します。
// prepare the multilevel collection elements as a nested Java array
int[][][] elements = { {{1}, {1, 2}}, {{2}, {2, 3}}, {{3}, {3, 4}} };
// create the ARRAY using the factory method
ARRAY array = oracle.jdbc.OracleConnection.createARRAY(sql_type_name, elements);
16.4.2 配列とその要素の取出し
この項では、結果セットからARRAYインスタンス全体を取り出す方法を最初に説明し、次にARRAYインスタンスから要素を取り出す方法について説明します。この項の内容は次のとおりです。
16.4.2.1 配列の取出しについて
oracle.sql.ARRAYオブジェクトを戻すgetARRAYメソッドを使用して、結果セットをOracleResultSetオブジェクトにキャストすることで、SQL配列を結果セットから取り出すことができます。結果セットをキャストするのを避けるには、java.sql.ResultSetインタフェースによって指定された標準のgetObjectメソッドを使用してデータを取得し、その出力をoracle.sql.ARRAYにキャストします。
16.4.2.2 データ取出しメソッド
ARRAYオブジェクトを作成した後は、次に示すoracle.sql.ARRAYクラスの3つのオーバーロード・メソッドのいずれかを使用して、データを取り出すことができます。
-
getArray -
getOracleArray -
getResultSet
Oracleは配列のすべての要素、またはサブセットを取り出すことができるメソッドも提供しています。
ノート:
構造化オブジェクトの配列を操作している場合は、Oracleは、オブジェクトをJavaにマップする方法を選択できるように、型マップを指定できる次の3つのメソッドのバージョンを提供します。
getOracleArray
getOracleArray()メソッドは、標準Arrayインタフェースでは指定されていないOracle固有の拡張機能です。getOracleArrayメソッドでは、配列の要素値を取り出してDatum[]配列に格納します。この要素は、元の配列のSQL型データに対応するoracle.sql.*データ型です。
構造化オブジェクトの配列では、このメソッドは要素のためにoracle.jdbc.OracleStructインスタンスを使用します。
また、getOracleArray(index,count)メソッドを使用すると、配列要素のサブセットを取得できます。
getResultSet
getResultSetメソッドは、ARRAYオブジェクトによって示される配列の要素が含まれる結果セットを戻します。結果セットは配列要素ごとに1行を含み、各行には2つの列があります。最初の列には、配列内でその要素を参照する索引が格納され、2つめの列には要素値が格納されます。VARRAYの場合、索引は配列内での要素の位置を表します。定義上、順序付けられていないネスト表の場合、索引は特定の問合せにおける要素の戻り順のみを反映します。
NESTED TABLEからデータを取り出すときは、getResultSetを使用することをお薦めします。NESTED TABLEの要素数には、制限はありません。メソッドから戻されたResultSetオブジェクトのポインタの初期値は、データの第1行です。nextメソッドおよび適切なgetXXXメソッドを使用すると、NESTED TABLEの内容を取得できます。また、getArrayを使用すると、NESTED TABLEのすべての内容が一度に戻されます。
getResultSetメソッドでは、接続のデフォルト型マップを使用して、OracleオブジェクトのSQL型とその対応するJavaデータ型間のマッピングを決定します。接続のデフォルト型マップを使用しない場合は、getResultSet(map)を使用して別の型マップを指定できます。
また、getResultSet(index,count)およびgetResultSet(index,count,map)メソッドを使用すると、配列のサブセットを取り出すことができます。
getArray
getArrayメソッドは、必要に応じてキャストできるjava.lang.Objectとして配列要素を戻す標準JDBCメソッドです。要素は、元の配列のSQL型データに対応するJava型データに変換されます。
また、getArray(index,count)メソッドを使用すると、配列要素のサブセットを取り出すことができます。
16.4.2.3 データ取出しメソッドの比較
配列要素を戻すためにgetOracleArrayを使用する場合は、そのメソッドがoracle.sql.Datumインスタンスを使用するため、SQLからJavaへのデータ変換を行う必要がなくなります。Datumクラスまたはそのサブクラスのインスタンス内にある文字以外のデータは、RAW SQL形式で保持されます。
getResultSetを使用してプリミティブ・データ型の配列を戻す場合、JDBCドライバはResultSetオブジェクトを戻します。このオブジェクトには、各要素ごとに、その要素を配列内で参照する索引と要素値が含まれます。たとえば:
ResultSet rset = intArray.getResultSet();
この場合、結果セットには、1つの配列要素ごとに1つの行があり、各行には2つの列があります。最初の列には、配列内でその要素を参照する索引が格納され、2つめの列には要素値が格納されます。
配列の要素が、Java型にマップするSQL型の場合、getArrayはこのJava型の要素の配列を戻します。getArrayメソッドの戻り型はjava.lang.Objectです。したがって、結果は使用する前にキャストする必要があります。
BigDecimal[] values = (BigDecimal[]) intArray.getArray();
ここで、intArrayはoracle.sql.ARRAYで、NUMBER型のVARRAYに対応しています。values配列にはjava.math.BigDecimal型の要素の配列が含まれます。これはSQL NUMBERデータ型が、デフォルトで、Oracle JDBCドライバによって、Java BigDecimalにマップされるためです。
ノート:
BigDecimalの使用は、リソースを大量に消費するJavaの操作です。Oracle JDBCは数値SQLデータをデフォルトでBigDecimalにマップするため、getArrayを使用するとパフォーマンスに影響を与える可能性があり、数値のコレクションの場合は推奨されません。
16.4.2.4 型マップに従った構造化オブジェクト配列の要素の取出し
デフォルトでは、構造化オブジェクトの要素を持つ配列を操作しているときに、getArrayまたはgetResultSetを使用すると、デフォルト・マッピングに従って配列のOracleオブジェクトが、対応するJavaデータ型にマップされます。これは、これらのメソッドでは、接続のデフォルト型マップを使用してマッピングが決定されるためです。
ただし、デフォルトの処理を変更する場合は、getArray(map)またはgetResultSet(map)メソッドを使用して、別のマッピングを含む型マップを指定できます。配列のOracleオブジェクトに対応するエントリが型マップに存在する場合は、配列の各オブジェクトは、その型マップで指定されている、対応するJava型にマップされます。たとえば:
Object[] object = (Object[])objArray.getArray(map);
この例のobjArrayはoracle.sql.ARRAYオブジェクトを表し、mapはjava.util.Mapオブジェクトを表します。
型マップに特定のOracleオブジェクトに対応するエントリが含まれない場合、要素はoracle.jdbc.OracleStructオブジェクトとして戻されます。
getResultSet(map)メソッドは、getArray(map)メソッドと同じように動作します。
関連トピック
16.4.2.5 配列要素のサブセットの取出し
配列の内容全体を取り出さない場合は、サブセットを取り出すことができるgetArray、getResultSetおよびgetOracleArrayのシグネチャを使用できます。配列のサブセットを取り出すには、索引と件数を渡して、取出しを開始する配列の位置および取り出す要素数を指定します。前の例と同様に、接続に対して型マップを指定するか、またはデフォルトの型マップを使用して、Java型に変換します。たとえば:
Object object = arr.getArray(index, count, map); Object object = arr.getArray(index, count);
getResultSetを使用した例です。
ResultSet rset = arr.getResultSet(index, count, map); ResultSet rset = arr.getResultSet(index, count);
getOracleArrayを使用した例です。
Datum[] arr = arr.getOracleArray(index, count);
arrはoracle.sql.ARRAYオブジェクト、indexはlong型、countはint型、mapはjava.util.Mapオブジェクトを表します。
ノート:
配列全体ではなく、配列のサブセットを取り出すことにパフォーマンス上の利点はありません。
16.4.2.6 oracle.sql.Datum配列への配列要素の取出し
oracle.sql.Datum[]配列を戻すには、getOracleArrayを使用します。戻される配列の要素は、元の配列要素のSQLデータ型に対応するoracle.sql.*型です。たとえば:
Datum arraydata[] = arr.getOracleArray();
arrはoracle.sql.ARRAYオブジェクトを表します。
次の例は、接続オブジェクトconnおよび文オブジェクトstmtがすでに作成済であることを前提としています。この例では、SQL型名NUM_ARRAYの配列がNUMBERデータのVARRAYを格納するために作成されます。NUM_ARRAYは、表VARRAY_TABLEに格納されます。
問合せは、VARRAY_TABLEの内容を選択します。結果セットはOracleResultSetにキャストされます。それに対してgetARRAYメソッドが適用され、配列データがmy_arrayに取得されます。これはoracle.sql.ARRAYオブジェクトです。
my_arrayはoracle.sql.ARRAY型の配列であるため、getSQLTypeNameメソッドおよびgetBaseTypeメソッドをこの配列に適用すれば、その配列の要素ごとに、その整数コードでSQL型名を戻すことができます。
次に、プログラムにより配列の内容が出力されます。NUM_ARRAYの内容はSQLデータ型NUMBERであるため、my_arrayの要素はBigDecimal型です。要素を使用するには、最初に、その要素をBigDecimalにキャストする必要があります。forループでは、配列の各値はBigDecimalにキャストされ、標準出力に出力されます。
stmt.execute ("CREATE TYPE num_varray AS VARRAY(10) OF NUMBER(12, 2)");
stmt.execute ("CREATE TABLE varray_table (col1 num_varray)");
stmt.execute ("INSERT INTO varray_table VALUES (num_varray(100, 200))");
ResultSet rs = stmt.executeQuery("SELECT * FROM varray_table");
ARRAY my_array = ((OracleResultSet)rs).getARRAY(1);
// return the SQL type names, integer codes,
// and lengths of the columns
System.out.println ("Array is of type " + array.getSQLTypeName());
System.out.println ("Array element is of type code " + array.getBaseType());
System.out.println ("Array is of length " + array.length());
// get Array elements
BigDecimal[] values = (BigDecimal[]) my_array.getArray();
for (int i=0; i<values.length; i++)
{
BigDecimal out_value = (BigDecimal) values[i];
System.out.println(">> index " + i + " = " + out_value.intValue());
}
getResultSetを使用して配列を取得する場合は、最初に結果セット・オブジェクトを取得し、次にnextメソッドを使用して操作を反復する必要があるので、注意が必要です。getIntメソッドでは、パラメータの索引を使用して、要素の索引および要素値を取り出します。
ResultSet rset = my_array.getResultSet();
while (rset.next())
{
// The first column contains the element index and the
// second column contains the element value
System.out.println(">> index " + rset.getInt(1)+" = " + rset.getInt(2));
}16.4.2.7 マルチ・レベル・コレクション要素へのアクセスについて
oracle.sql.ARRAYクラスは、コレクション要素にアクセスするために、オーバーロードされた3つのメソッドを提供します。JDBCドライバは、これらのメソッドをマルチ・レベル・コレクションをサポートするように拡張します。これらのメソッドを次に示します。
-
getArrayメソッド -
getOracleArrayメソッド -
getResultSetメソッド
getArrayメソッドは、コレクション要素を保持するJava配列を戻します。配列要素の型は、コレクション要素の型とJDBCのデフォルトの変換マトリックスによって決まります。
たとえば、getArrayメソッドは、SQL NUMBER型のコレクションのjava.math.BigDecimal配列を戻します。getOracleArrayメソッドは、Datum形式でコレクション要素を保持するDatum配列を戻します。マルチ・レベル・コレクションの場合、getArrayメソッドおよびgetOracleArrayメソッドはいずれも、oracle.sql.ARRAY要素のJava配列を戻します。
getResultSetメソッドは、マルチ・レベル・コレクション要素をラップするResultSetオブジェクトを戻します。マルチ・レベル・コレクションの場合、JDBCアプリケーションはResultSetクラスのgetObject、getARRAYまたはgetArrayメソッドを使用して、oracle.sql.ARRAYのインスタンスとしてコレクション要素にアクセスします。
次のコードは、getOracleArray、getArrayおよびgetResultSetメソッドの使用方法を示します。
Connection conn = ...; // make a JDBC connection
Statement stmt = conn.createStatement ();
ResultSet rset = stmt.executeQuery ("select col2 from tab2 where idx=1");
while (rset.next())
{
ARRAY varray3 = (ARRAY) rset.getObject (1);
Object varrayElems = varray3.getArray (1);
// access array elements of "varray3"
Datum[] varray3Elems = (Datum[]) varrayElems;
for (int i=0; i<varray3Elems.length; i++)
{
ARRAY varray2 = (ARRAY) varray3Elems[i];
Datum[] varray2Elems = varray2.getOracleArray();
// access array elements of "varray2"
for (int j=0; j<varray2Elems.length; j++)
{
ARRAY varray1 = (ARRAY) varray2Elems[j];
ResultSet varray1Elems = varray1.getResultSet();
// access array elements of "varray1"
while (varray1Elems.next())
System.out.println ("idx="+varray1Elems.getInt(1)+"
value="+varray1Elems.getInt(2));
}
}
}
rset.close ();
stmt.close ();
conn.close (); 16.4.3 配列の文オブジェクトへの引渡し
この項では、プリペアド文オブジェクトまたはコール可能文オブジェクトに配列を渡す方法について説明します。
配列のプリペアド文への引渡し
次の手順に従って、配列をプリペアド文に渡します。
ノート:
配列は、INまたはOUTバインド変数として使用できます。
-
プリペアド文に
oracle.sql.ARRAYオブジェクトとして渡す配列を定義します。ARRAY array = oracle.jdbc.OracleConnection.createARRAY(sql_type_name, elements);
sql_type_nameは配列のユーザー定義SQL型名を指定するJava文字列を表し、elementsは要素のJava配列を含むjava.lang.Objectを表します。 -
実行するSQL文を含む
java.sql.PreparedStatementオブジェクトを作成します。 -
プリペアド文を
OraclePreparedStatementにキャストし、setARRAY()を使用して、プリペアド文に配列を渡します。(OraclePreparedStatement)stmt.setARRAY(parameterIndex, array);
parameterIndexはパラメータ索引を表し、arrayは手順2で作成したoracle.sql.ARRAYオブジェクトを表します。 -
プリペアド文を実行します。
配列のコール可能文への引渡し
16.5 型マップを使用した配列要素のマップ
配列にOracleオブジェクトが含まれる場合は、型マップを使用して、配列のオブジェクトを、対応するJavaクラスに関連付けることができます。型マップを指定しない場合または型マップに特定のOracleオブジェクトのエントリが含まれない場合、各要素はoracle.jdbc.OracleStructオブジェクトとして戻されます。
型マップを使用して、配列のOracleオブジェクトと対応するJavaクラスとのマッピングを決定するときは、マップに適切なエントリを追加する必要があります。
次の例では、型マップを使用して配列要素をカスタムJavaオブジェクト・クラスにマップする方法を説明します。この例の配列は、NESTED TABLEです。この例では、まず、名前属性と従業員番号属性が設定されているEMPLOYEEオブジェクトを定義します。EMPLOYEE_LISTはEMPLOYEEオブジェクトのNESTED TABLE型です。次に、会社内の部署名および各部署の従業員名を格納するEMPLOYEE_TABLEを作成します。EMPLOYEE_TABLEの中では、従業員はEMPLOYEE_LIST表の形式で格納されます。
stmt.execute("CREATE TYPE EMPLOYEE AS OBJECT
(EmpName VARCHAR2(50),EmpNo INTEGER))");
stmt.execute("CREATE TYPE EMPLOYEE_LIST AS TABLE OF EMPLOYEE");
stmt.execute("CREATE TABLE EMPLOYEE_TABLE (DeptName VARCHAR2(20),
Employees EMPLOYEE_LIST) NESTED TABLE Employees STORE AS ntable1");
stmt.execute("INSERT INTO EMPLOYEE_TABLE VALUES ("SALES", EMPLOYEE_LIST
(EMPLOYEE('Susan Smith', 123), EMPLOYEE('Lee Brown', 124)))");
SALES部門に属するすべての従業員をカスタム・オブジェクト・クラスEmployeeObjのインスタンスの配列に取り込む場合は、EMPLOYEE SQL型とEmployeeObjカスタム・オブジェクト・クラス間のマッピングを指定するために、型マップにエントリを追加する必要があります。
これを実行するには、まず文と結果セット・オブジェクトを作成し、次に、SALES部門に関連付けられているEMPLOYEE_LISTを結果セットに選択します。getARRAYメソッドを使用してEMPLOYEE_LISTをARRAYオブジェクト(次の例ではemployeeArray)に取得できるように、結果セットをOracleResultSetにキャストします。
この例のEmployeeObjカスタム・オブジェクト・クラスは、SQLDataインタフェースを実装しています。
Statement s = conn.createStatement();
OracleResultSet rs = (OracleResultSet)s.executeQuery
("SELECT Employees FROM employee_table WHERE DeptName = 'SALES'");
// get the array object
ARRAY employeeArray = ((OracleResultSet)rs).getARRAY(1);
EMPLOYEE_LISTオブジェクトを取り出したので、既存の型マップを取得し、SQL型EMPLOYEEをJava型EmployeeObjにマップするエントリを追加します。
// add type map entry to map SQL type
// "EMPLOYEE" to Java type "EmployeeObj"
Map map = conn.getTypeMap();
map.put("EMPLOYEE", Class.forName("EmployeeObj"));
次に、EMPLOYEE_LISTからSQL EMPLOYEEオブジェクトを取り出します。この操作をするには、employeeArray配列オブジェクトのgetArrayメソッドをコールします。このメソッドにより、オブジェクト配列が戻されます。getArrayメソッドでは、employeesオブジェクト配列にEMPLOYEEオブジェクトが戻されます。
// Retrieve array elements Object[] employees = (Object[]) employeeArray.getArray();
最後にループを作成して、各EMPLOYEE SQLオブジェクトに、EmployeeObj Javaオブジェクトのempを割り当てます。
// Each array element is mapped to EmployeeObj object.
for (int i=0; i<employees.length; i++)
{
EmployeeObj emp = (EmployeeObj) employees[i];
...
}