[Oracle] 「結合配列」と「ネストした表」の違い(特に初期化方法) | Archive Redo Blog

Archive Redo Blog

DBエンジニアのあれこれ備忘録

PL/SQLで配列を扱うにはPL/SQLコレクション型と呼ばれるデータ型を使用します。

PL/SQLコレクション型には「VARRAY」、「結合配列(索引付き表)」、「ネストした表」の3つのタイプがありますが、このうち「結合配列」、「ネストした表」は定義方法や使用方法がよく似ており、一見何が違うのかよくわかりません。

しかし、その違いを認識せずに何となく使っていると、思わぬトラブルに悩まされることがあります。

特にコレクションの初期化には注意が必要です。

「結合配列」と「ネストした表」の定義方法の違い
「結合配列」と「ネストした表」は定義方法が非常によく似ています。

結合配列
DECLARE
    type table_type IS TABLE OF VARCHAR2(100)    --型の定義
        INDEX BY BINARY_INTEGER;
    wk_table    table_type;                      --変数の宣言
      .
      .
      .

ネストした表
DECLARE
    type table_type IS TABLE OF VARCHAR2(100);   --型の定義
    wk_table    table_type;                      --変数の宣言
      .
      .
      .


いずれも型を定義して、定義した型を指定した変数を宣言するという点では全く同様で、結合配列の定義に"INDEX BY key_type"という句が付いているのが唯一の違いとなっています。

この"INDEX BY key_type"で指定しているのは結合配列のキーで、BINARY_INTEGER、PLS_INTEGER、VARCHAR2(n)などを指定することができる。結合配列の場合はここで指定したタイプのキーを使用して配列にアクセスするというわけです。


キーの値は必ずしも連続している必要はありません。

一方、ネストした表の場合は配列への格納順に 1 から始まる連続した添字が与えれ、この添字を指定して配列にアクセスするという仕様になっており、この点が両者の仕様の大きな違いとなっています。

ただ、結合配列でも、数値型(BINARY_INTEGERまたはPLS_INTEGER)のキーを使用し、そのキーに 1 からの連番を振って配列に値を格納するような使い方をすることも結構多いので、そういう使い方ばかりをしていると両者の違いがあいまいになりがちです。

「結合配列」と「ネストした表」の初期化方法の違い
「結合配列」、「ネストした表」も初期化をしないと参照することができません。

初期化していないコレクション要素を参照しようとすると以下のようなエラーが発生します。

結合配列
ORA-01403: データが見つかりません。
ネストした表(コレクションそのものが初期化されていない場合)
ORA-06531: 参照しているコレクションは初期化されていません。
ネストした表(初期化していない添字のコレクション要素を指定した場合)
ORA-06533: サブスクリプトがカウントを超えています。

※なぜかエラーコードとメッセージが異なりますが、いずれも初期化されていないことを示しています。

というわけで、「結合配列」、「ネストした表」を参照する前には必ず初期化しなければならないのですが、その方法は全く違います。

結合配列
DECLARE
    type table_type IS TABLE OF VARCHAR2(10)    --型の定義
        INDEX BY BINARY_INTEGER;
    wk_weekday_table    table_type;             --変数の宣言
BEGIN
    wk_weekday_table(1) := '日';
    wk_weekday_table(2) := '月';
    wk_weekday_table(3) := '火';
    wk_weekday_table(4) := '水';
    wk_weekday_table(5) := '木';
    wk_weekday_table(6) := '金';
    wk_weekday_table(7) := '土';
      .
      .
      .

ネストした表
DECLARE
    type table_type IS TABLE OF VARCHAR2(10);    --型の定義
    wk_weekday_table    table_type;              --変数の宣言
BEGIN
    wk_weekday_table := table_type('日','月','火','水','木','金','土');    --初期化
      .
      .
      .


結合配列の場合、初期化を行うための特別な文はなく、キーを指定して値を代入していくことによって初期化を行います。

一方、ネストした表の場合、コンストラクタを使用して初期化を行います。


上記の例では実行部で初期化していますが、以下のように宣言部で変数の宣言時に初期化することもできます。

DECLARE
    type table_type IS TABLE OF VARCHAR2(10);    --型の定義
    wk_weekday_table    table_type               --変数の宣言と初期化
        := table_type('日','月','火','水','木','金','土'); 
      .
      .
      .

この初期化方法の違いをはっきりと認識せずに何となく使っていると前述のエラーに遭遇して悩むことになります。

これらのエラーはコンパイル時には検知できず、実行時にも特定の条件に当てはまる時にしか発生しないようなこともあるので、注意しなければなりません。

コレクション型を使用する上で最も遭遇する可能性の高いトラブルがこの初期化の問題ではないでしょうか。

※ただし、「結合配列」、「ネストした表」ともSELECT INTO文のBULK COLLECT句を使う場合は同じ方法で初期化できます。

SELECT DISTINCT JOB BULK COLLECT INTO wk_job_table FROM EMP;

その他の違い
その他、参照方法や代入方法に関しては特に大きな違いはないのですが、もっと根本的なところに1つ大きな違いがあります。

それは「結合配列」はPL/SQLでしか使用できないが、「ネストした表」はデータベースのテーブルに列として格納することもできるという点です。

この仕様の違いは、添字の仕様の違いと合わせて、プログラムの中でどのコレクション型を選択するべきかを判断するための重要な要素となります。

しかし、その辺の詳しい解説は他に譲ります^^ゞ


参考:「PL/SQLユーザーズ・ガイドおよびリファレンス」