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

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

第13回 「コレクション変数について」

2012.03.19

今回は前回のレコード変数と同様に複雑な構造を持った変数として、コレクション変数について解説します。

コレクション変数とは同じデータ型の値を複数格納できる変数です。
そのデータ型はNUMBERのような基本的な単純なデータ型でもいいし、ユーザが定義するレコード型のような複雑なデータ型でも可能です。

コレクション変数の一つの応用例として、コレクション変数を明示カーソル処理で使用することができます。明示カーソル処理ではいったんフェッチした行をもう一度フェッチすることはできません。どうしてもそれを行うのであれば、カーソルをいったんクローズして再びオープンし目的の行まで読み飛ばしのフェッチを繰り返すような、非常に無理のあるロジックが必要になります。パフォーマンス的にも好ましくなく現実的ではありません。そんなとき、コレクションを用いればエレガントに問題解決できます。すなわちフェッチした行をカーソル変数に格納しておけば、カーソルをクローズ後であっても、カーソル変数の値は参照できるので、フェッチ済みの行を使用できます。

では、そういった事例紹介の前にコレクションの文法を解説します。

コレクション変数は、レコード変数と同じようにまず型を宣言し、次にその型を使ってコレクション変数を宣言します。

コレクションの型には、正確には3種類あります。

・結合配列(PL/SQL表、索引付表ともいう)
・ネストした表
・可変配列(VARRAYともいう)

それぞれ特徴や使い分けがありますが、ここでは一番操作しやすい結合配列(PL/SQL表、索引付表ともいう)を紹介します。

結合配列では、キーと値のペアを個数の上限なしに自由に格納できます。キー値が連続している必要はありません。一般的なプログラミング用語で「配列」をご存知の方は多いと思います。コレクションは配列のようなものであり、キーは配列の添え字のような役割をはたします。厳密には配列とコレクションは違うものですが、結合配列は配列のようなものです。ここではその違いまでは説明しません。では以下に結合配列の宣言の構文、基本的な操作方法を説明します。

まず、宣言は「型の宣言」、「変数の宣言」の2段階です。

<型の宣言>
TYPE 型名 IS TABLE OF データ型 INDEX BY キーのデータ型;
<変数の宣言>
変数名 型名;

ここで、キーのデータ型ですが、整数または文字列のいずれかです。キーが整数の場合は、PLS_INTEGERまたはBINARY_INTEGERを指定します。文字列の場合は、VARCHAR2(n) を指定します。(nはサイズ) キーが整数の場合でも、キーが連続する必要はありません。キーがマイナスでも整数であればOKです。必要があれば、文字列をキーに使うこともできます。

結合配列はキーを指定して自由に代入できます。新しいキーで代入すればそのキーのエントリーが追加されます。既存のキーで代入すれば、そのキーでの値を更新することになります。

コレクション変数(キー値) := 値;

参照するときもキーを指定して参照します。例えば、

DBMS_OUTPUT.PUT_LINE(コレクション変数(キー値));

では、以下は簡単な具体例です。

  1  DECLARE
  2    TYPE  A_TYPE IS TABLE OF VARCHAR2(10) INDEX BY BINARY_INTEGER;
  3    A     A_TYPE;
  4  BEGIN
  5    A(10) := 'ABC';
  6    A(20) := 'DEF';
  7    A(30) := 'GHI';
  8    DBMS_OUTPUT.PUT_LINE(A(20));
  9* END;
SQL> /
DEF

PL/SQLプロシージャが正常に完了しました。

まず、宣言部の2行目で、値がVARCHAR2(10)型でキーがBINARY_INTEGER型の結合配列についてA_TYPEという名前で型を宣言しています。次に3行目でそのA_TYPE型を使ってAという変数を宣言しています。これで変数ができました。次に実行部の5行目から7行目にかけて、キーが10, 値が'ABC'、キーが20, 値が'DEF'、キーが30, 値が'DEF'で 結合配列Aに値を格納しています。8行目では、キー値が20の結合配列Aの値、すなわち、'DEF'を表示しています。

ご覧のようにキー値は配列の添え字とは違って、連続した数値でなくても結構です。

では、以下にカーソル処理と組み合わせた応用例を解説します。

  1  DECLARE
  2     CURSOR C1 IS SELECT DEPTNO, DNAME FROM DEPT;
  3     REC      C1%ROWTYPE;
  4     TYPE     REC_TAB_TYPE IS TABLE OF C1%ROWTYPE INDEX BY BINARY_INTEGER;
  5     REC_TAB  REC_TAB_TYPE;
  6     I        BINARY_INTEGER := 1;
  7  BEGIN
  8     OPEN C1;
  9     LOOP
 10       FETCH C1 INTO REC;
 11       EXIT WHEN C1%NOTFOUND;
 12       DBMS_OUTPUT.PUT_LINE( 'カーソルから ' || REC.DNAME);
 13       REC_TAB(I) := REC;
 14       I := I + 1;
 15     END LOOP;
 16     CLOSE C1;
 17     DBMS_OUTPUT.PUT_LINE('------------------------------------------------');
 18     FOR I IN 1..REC_TAB.COUNT LOOP
 19        DBMS_OUTPUT.PUT_LINE( 'コレクションから ' || REC_TAB(I).DNAME);
20 END LOOP;
21* END;
SQL> /
カーソルから ACCOUNTING
カーソルから RESEARCH
カーソルから SALES
カーソルから OPERATIONS
------------------------------------------------
コレクションから ACCOUNTING
コレクションから RESEARCH
コレクションから SALES
コレクションから OPERATIONS

PL/SQLプロシージャが正常に完了しました。

SQL>

上記の例の補足を以下に書きました。

2行目 明示カーソルの宣言
3行目 そのカーソルのレコード型変数の宣言
4行目 そのカーソルのレコード型のコレクションの型の宣言(このようにレコード型のコレクションも可能です)
5行目 その型のコレクション変数の宣言
6行目 コレクションのキーの変数の宣言
8~15行目 明示カーソルの1行1行を画面表示するとともに、コレクション変数に格納している
16行目 明示カーソルをクローズ
18~20 コレクション変数の内容を1件ずつ画面表示している

18行目 「REC_TAB.COUNT」はコレクションの要素の数を表す。上記の例では、4である。
したがって、FOR I IN 1..REC_TAB.COUNT LOOP キーI を 1から4までループという意味である。

いかがでしょうか? 明示カーソルで取得した行レコードをコレクション変数に格納して明示カーソルをクローズ後にそれらのデータを再度、使用している様子が確認できると思います。

上記の例では、コレクションのキーは1番から連続した整数を使っていましたが、連続している必要はありません。ですから、部門番号のように、10,20,30といった不連続の値でも可能です。

いかがでしょうか? 結合配列の使い方がお解りいただけましたか?いろいろと応用できそうですね。それでは今回はここまでにします。

次回もご期待ください。

先頭へ戻る