【Oracle】ORA-06531の原因と解決方法|Reference to uninitialized collection の直し方

【Oracle】ORA-06531の原因と解決方法|Reference to uninitialized collection の直し方 Oracle

ORA-06531: Reference to uninitialized collection は、Oracle PL/SQLで初期化していないコレクションを参照した時に発生するエラーです。特にネスト表やVARRAYを宣言しただけで、コンストラクタを呼ばずに COUNTEXTEND、要素代入、ループ処理をしようとした時に起きます。

Oracle公式のエラー説明でも、未初期化のコレクションを参照していることが原因で、対象コレクションを初期化してから使う必要があります。PL/SQLのコレクション全体の基本は PL/SQLコレクション型完全ガイド も参考になります。

先に結論
ネスト表・VARRAYは、宣言しただけでは空ではなく NULL状態のコレクション です。l_list := t_num_list(); のようにコンストラクタで初期化してから、必要に応じて EXTEND して要素を入れます。初期化済みだが要素数が足りない場合は、ORA-06531ではなく ORA-06533: Subscript beyond count になりやすいです。
スポンサーリンク

ORA-06531とは

ORA-06531は、PL/SQLの事前定義例外 COLLECTION_IS_NULL に対応するエラーです。コレクション変数そのものがNULL状態のまま、要素やメソッドに触れた時に発生します。

状態 意味 起きやすいエラー
未初期化 コレクション変数がNULL ORA-06531
初期化済み・要素0件 空のコレクション 要素参照でORA-06533になりやすい
初期化済み・要素あり 通常利用できる状態 添字や型の問題がなければOK
連想配列 コンストラクタを使わないPL/SQLコレクション ネスト表/VARRAYとは扱いが違う

発生する典型例

次の例では、ネスト表型の変数を宣言しただけで、コンストラクタを呼んでいません。この状態で EXTEND や要素代入をすると、ORA-06531が発生します。

ora06531-uninitialized.sql
DECLARE
  TYPE t_num_list IS TABLE OF NUMBER;
  l_ids t_num_list;
BEGIN
  l_ids.EXTEND;
  l_ids(1) := 100;
END;
/

-- ORA-06531: Reference to uninitialized collection
-- ORA-06512: at line 5

ここで重要なのは、l_ids は「空の配列」ではなく「NULL状態のコレクション」だという点です。ORA-06512の行番号の読み方は ORA-06512の原因と読み方 で詳しく整理しています。

基本の直し方

ネスト表やVARRAYは、型名と同じコンストラクタを呼んで初期化します。空で始めたい場合でも、空のコンストラクタを代入してから使います。

initialize-nested-table.sql
DECLARE
  TYPE t_num_list IS TABLE OF NUMBER;
  l_ids t_num_list := t_num_list();
BEGIN
  l_ids.EXTEND;
  l_ids(1) := 100;

  DBMS_OUTPUT.PUT_LINE(l_ids(1));
END;
/
やりたいこと 書き方 注意点
空で初期化する l_ids := t_num_list(); この時点では要素数0件
1件追加する l_ids.EXTEND; 追加後にl_ids(l_ids.COUNT)へ代入
初期値付きで作る t_num_list(10, 20, 30) 最初から3要素ある
再初期化する l_ids := t_num_list(); 既存要素は消える

症状別の最短修正

ORA-06531は、どこで未初期化になっているかによって直し方が少し変わります。まずは次の表で、該当する症状から確認します。

症状 原因になりやすい箇所 最短修正
l_list.EXTENDで失敗 宣言後にコンストラクタを呼んでいない l_list := t_list(); を先に実行
l_list(1) := ...で失敗 未初期化、または要素追加前 初期化してからEXTEND
呼び出し元で失敗 関数戻り値やOUT引数がNULLコレクション 0件でも空コレクションを返す
オブジェクト属性で失敗 親オブジェクト生成時に子コレクションがNULL 属性にもtype_name()を渡す
修正後にORA-06533になる 初期化はできたが要素数が足りない COUNT確認とEXTENDを追加

空のコレクションとNULLコレクションの違い

ORA-06531で混乱しやすいのは、空とNULLが違うことです。初期化済みで要素が0件のコレクションは空です。一方、宣言しただけのネスト表やVARRAYはNULL状態です。

empty-vs-null-collection.sql
DECLARE
  TYPE t_num_list IS TABLE OF NUMBER;
  l_null_list  t_num_list;
  l_empty_list t_num_list := t_num_list();
BEGIN
  -- l_null_list.COUNT は ORA-06531 になり得る
  DBMS_OUTPUT.PUT_LINE(l_empty_list.COUNT); -- 0
END;
/

EXISTS はNULLコレクションにも使える場面がありますが、通常の実装では「使う前に初期化する」方針にした方が読みやすく、安全です。

ORA-06531とORA-06533の違い

ORA-06531と混同しやすいのが ORA-06533: Subscript beyond count です。どちらもコレクションで出ますが、原因は違います。

エラー 状態 対処
ORA-06531 コレクション自体が未初期化 l_ids.EXTEND の前にコンストラクタ未実行 コンストラクタで初期化する
ORA-06533 初期化済みだが要素数が足りない l_ids(1) に代入したいがCOUNT=0 EXTENDしてから代入する
ORA-06502 要素の型や桁が合わない 文字列長不足、数値変換エラー ORA-06502を確認する
ora06533-after-initialize.sql
DECLARE
  TYPE t_num_list IS TABLE OF NUMBER;
  l_ids t_num_list := t_num_list();
BEGIN
  l_ids(1) := 100;
END;
/

-- 初期化済みだが要素がないため、ORA-06533になりやすい
-- l_ids.EXTEND; を先に実行する

VARRAYの場合

VARRAYも、宣言しただけではNULL状態です。ネスト表と同じく、コンストラクタで初期化してから使います。ただしVARRAYには最大要素数があるため、LIMIT も意識します。

initialize-varray.sql
DECLARE
  TYPE t_code_list IS VARRAY(3) OF VARCHAR2(10);
  l_codes t_code_list := t_code_list();
BEGIN
  l_codes.EXTEND;
  l_codes(1) := 'A001';

  DBMS_OUTPUT.PUT_LINE(l_codes.COUNT || '/' || l_codes.LIMIT);
END;
/

オブジェクト型の属性で起きる場合

実務で多いのが、オブジェクト型の属性としてネスト表を持っているケースです。オブジェクト自体を生成していても、コレクション属性を初期化していないとORA-06531になります。

object-attribute-bad.sql
CREATE TYPE t_num_list AS TABLE OF NUMBER;
/
CREATE TYPE t_order_obj AS OBJECT (
  order_id NUMBER,
  item_ids t_num_list
);
/

DECLARE
  l_order t_order_obj := t_order_obj(1001, NULL);
BEGIN
  l_order.item_ids.EXTEND;
END;
/

-- item_ids がNULLなので ORA-06531
object-attribute-good.sql
DECLARE
  l_order t_order_obj := t_order_obj(1001, t_num_list());
BEGIN
  l_order.item_ids.EXTEND;
  l_order.item_ids(1) := 501;
END;
/

BULK COLLECTで扱う場合

BULK COLLECT でコレクションに取得する場合も、後続処理では件数確認が重要です。取得結果が0件なら、ループや要素参照で別のエラーにつながることがあります。大量データ処理は BULK COLLECT / FORALL完全ガイド も参考になります。

bulk-collect-count-check.sql
DECLARE
  TYPE t_num_list IS TABLE OF NUMBER;
  l_ids t_num_list;
BEGIN
  SELECT employee_id
  BULK COLLECT INTO l_ids
  FROM employees
  WHERE department_id = -1;

  IF l_ids.COUNT > 0 THEN
    DBMS_OUTPUT.PUT_LINE(l_ids(1));
  END IF;
END;
/

明示的カーソルや BULK COLLECT LIMIT を使う処理では、明示的カーソル完全ガイド も合わせて見ると切り分けやすいです。

初期化漏れを防ぐ書き方

ORA-06531は、宣言場所で初期化する、または初期化関数を通すことでかなり防げます。パッケージ変数、OUT引数、オブジェクト属性では特に初期化漏れが起きやすいです。

initialize-at-declaration.sql
DECLARE
  TYPE t_num_list IS TABLE OF NUMBER;
  l_ids t_num_list := t_num_list();
BEGIN
  NULL;
END;
/
return-empty-collection.sql
CREATE OR REPLACE PACKAGE pkg_order AS
  TYPE t_num_list IS TABLE OF NUMBER;
  FUNCTION empty_ids RETURN t_num_list;
END;
/

CREATE OR REPLACE PACKAGE BODY pkg_order AS
  FUNCTION empty_ids RETURN t_num_list IS
  BEGIN
    RETURN t_num_list();
  END;
END;
/

OUT引数・関数戻り値でNULLを返す場合

呼び出し先ではエラーにならず、呼び出し元でORA-06531になる場合は、OUT引数や関数戻り値としてNULLコレクションを返している可能性があります。0件を表したい場合でも、NULLではなく空コレクションを返す方が安全です。

bad-return-null-collection.sql
CREATE OR REPLACE FUNCTION get_order_ids RETURN pkg_order.t_num_list IS
  l_ids pkg_order.t_num_list;
BEGIN
  RETURN l_ids;
END;
/

-- 呼び出し元で result.COUNT や result.EXTEND を呼ぶと ORA-06531 になり得る
good-return-empty-collection.sql
CREATE OR REPLACE FUNCTION get_order_ids RETURN pkg_order.t_num_list IS
  l_ids pkg_order.t_num_list := pkg_order.t_num_list();
BEGIN
  RETURN l_ids;
END;
/

-- 0件でも空コレクションを返す

調査手順

実際の障害対応では、ORA-06531の直後に出る ORA-06512 の行番号から、USER_SOURCE で未初期化の変数を探します。ログに DBMS_UTILITY.FORMAT_ERROR_BACKTRACE を残しておくと、後から行番号を追いやすくなります。

check-user-source-ora06531.sql
SELECT line,
       text
FROM user_source
WHERE name = 'PKG_ORDER'
  AND type = 'PACKAGE BODY'
  AND line BETWEEN 120 AND 140
ORDER BY line;
順番 見る場所 確認内容
1 ORA-06512の最初のオブジェクト付き行 どのプロシージャ、パッケージ、行番号か
2 該当行のコレクション変数 宣言時または直前で初期化しているか
3 代入・引数・戻り値 NULLコレクションを受け取っていないか
4 オブジェクト属性 属性のネスト表/VARRAYを初期化しているか
5 例外ログ エラー番号とバックトレースが残っているか

ログ設計は DBMS_UTILITY完全ガイド、例外処理の全体像は PL/SQL例外処理ガイド が参考になります。

よくある原因と対処一覧

原因 症状 対処
宣言しただけで使っている l_list.EXTENDでORA-06531 宣言時に:= type_name();
プロシージャのOUT引数にNULLを返している 呼び出し元でCOUNTや要素参照時に失敗 0件でも空コレクションを返す
オブジェクト属性がNULL obj.items.EXTENDで失敗 オブジェクト生成時に属性もコンストラクタで初期化
初期化と要素追加を混同している ORA-06531修正後にORA-06533 EXTEND後に添字代入
例外を握りつぶしている 原因行が分からない バックトレースをログに残してRAISE

チェックリスト

項目 OKの状態
ネスト表・VARRAYを初期化した type_name() を代入している
要素代入前にEXTENDした COUNT が必要な添字以上になっている
OUT引数や戻り値でNULLを返していない 0件なら空コレクションを返している
オブジェクト属性も初期化した 親オブジェクトだけでなく子コレクションも生成済み
ORA-06512の行番号を確認した 発生行と呼び出し元を分けて読んでいる

よくある質問

宣言しただけでは空のコレクションになりませんか?

ネスト表やVARRAYは、宣言しただけではNULL状態です。空にしたい場合でも、コンストラクタで初期化します。

EXTENDしているのにORA-06531になります

EXTEND 自体をNULLコレクションに対して呼んでいる可能性があります。先に l_list := t_list(); のように初期化します。

ORA-06531とORA-06533はどちらを見ればよいですか?

未初期化ならORA-06531、初期化済みだが要素数不足ならORA-06533です。まずコンストラクタ、その次にEXTENDの有無を確認します。

連想配列でもコンストラクタが必要ですか?

連想配列はネスト表やVARRAYと違い、コンストラクタを使いません。この記事の主な対象は、コンストラクタで初期化するネスト表とVARRAYです。

まとめ

ORA-06531は、未初期化のPL/SQLコレクションを参照した時に発生するエラーです。ネスト表やVARRAYは、宣言しただけでは空ではなくNULL状態なので、type_name() で初期化してから EXTEND や要素代入を行います。

ORA-06531を直した後に添字エラーが出る場合は、初期化はできていても要素数が足りない可能性があります。ORA-06512の行番号を見ながら、コンストラクタ、EXTEND、COUNT確認、例外ログの順に確認するのが近道です。

参考

ORA-06531 – Oracle Database Error Help

PL/SQL Collections and Records – Oracle Database PL/SQL Language Reference

Collection Method Invocation – Oracle Database PL/SQL Language Reference