ORA-06533: Subscript beyond count は、Oracle PL/SQLのコレクションで、存在しない要素番号を参照・代入した時に発生するエラーです。ネスト表やVARRAYを初期化していても、EXTEND で要素を増やす前に l_list(1) へ代入したり、COUNT=0 の状態で1件目を読んだりすると発生します。
Oracle公式のORA-06533説明では、添字がVARRAYの要素数を超えている、またはネスト表に対して大きすぎることが原因で、必要に応じて明示的に EXTEND することが対処として示されています。
ORA-06533が出たら、まず
COUNT と参照している添字を確認します。要素を追加したいなら EXTEND してから代入し、読み取りたいなら COUNT > 0 や EXISTS で確認します。未初期化なら ORA-06531、初期化済みで要素数不足ならORA-06533です。ORA-06533とは
ORA-06533は、PL/SQLコレクションの添字が、現在保持している要素数の範囲を超えた時に出ます。コレクション自体は初期化済みであっても、要素がまだ作られていない場合は参照できません。
| 状態 | 例 | 起きやすいエラー |
|---|---|---|
| 未初期化 | l_ids t_num_list; のまま使う |
ORA-06531 |
| 初期化済み・0件 | l_ids := t_num_list(); l_ids(1) |
ORA-06533 |
| 初期化済み・1件 | l_ids(2) を参照 |
ORA-06533 |
| 要素追加済み | EXTEND 後に範囲内を参照 |
正常 |
発生する典型例
次の例では、ネスト表を空で初期化していますが、要素を追加していません。そのため l_ids(1) へ代入しようとした時点でORA-06533になります。
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: Subscript beyond count -- ORA-06512: at line 5
このケースは未初期化ではありません。初期化はできていますが、要素数が0件のまま1件目に触っているのが原因です。ORA-06512の行番号の読み方は ORA-06512の原因と読み方 も参考になります。
基本の直し方
要素を追加してから代入する場合は、先に EXTEND します。最後に追加した要素へ代入するなら、l_list(l_list.COUNT) を使うと添字ずれを避けやすいです。
DECLARE TYPE t_num_list IS TABLE OF NUMBER; l_ids t_num_list := t_num_list(); BEGIN l_ids.EXTEND; l_ids(l_ids.COUNT) := 100; DBMS_OUTPUT.PUT_LINE(l_ids(1)); END; /
| やりたいこと | 安全な書き方 | 理由 |
|---|---|---|
| 1件追加する | EXTENDしてl_list(COUNT)へ代入 |
追加位置に確実に入れられる |
| 複数件追加する | EXTEND(n)後に範囲内へ代入 |
先に枠を作る |
| 1件目を読む | IF l_list.COUNT > 0 THEN |
0件時の参照を避ける |
| 特定添字を読む | IF l_list.EXISTS(i) THEN |
削除済み要素にも対応しやすい |
症状別の最短修正
ORA-06533は、代入で出ているのか、読み取りで出ているのかによって直し方が変わります。まずは発生行の操作を見て、次のように切り分けます。
| 症状 | 原因になりやすい箇所 | 最短修正 |
|---|---|---|
l_list(1) := valueで失敗 |
要素追加前に代入している | EXTENDしてからl_list(COUNT)へ代入 |
l_list(1)の読み取りで失敗 |
COUNT=0なのに1件目を読んでいる |
COUNT > 0を確認 |
| ループ中に途中で失敗 | 固定上限や別変数の件数で回している | 1 .. l_list.COUNTを使う |
FIRST .. LASTで失敗 |
DELETE後の穴あき要素を読んでいる |
EXISTS(i)を確認 |
BULK COLLECT後に失敗 |
取得0件または想定件数未満 | 参照前にCOUNTを見て分岐 |
ORA-06531との違い
ORA-06531とORA-06533は、どちらもコレクションで出ますが原因が違います。切り分けでは、まずコレクション自体が初期化済みか、その次に要素数が足りているかを見ます。
| エラー | 状態 | 確認すること | 対処 |
|---|---|---|---|
ORA-06531 |
コレクションがNULL | コンストラクタを呼んだか | t_list() で初期化 |
ORA-06533 |
初期化済みだが要素数不足 | COUNT と添字 |
EXTEND または範囲チェック |
ORA-06502 |
値や型が合わない | 文字列長、数値変換、代入先型 | ORA-06502を確認 |
未初期化コレクションの詳細は ORA-06531の原因と解決方法 で整理しています。PL/SQLコレクション全体の基礎は PL/SQLコレクション型完全ガイド も合わせて確認してください。
COUNTを使った範囲チェック
単純に1から COUNT まで詰まっているネスト表やVARRAYなら、1 .. l_list.COUNT のループが使いやすいです。ただし、DELETE で途中の要素を削除している場合は、EXISTS も使います。
DECLARE
TYPE t_num_list IS TABLE OF NUMBER;
l_ids t_num_list := t_num_list(10, 20, 30);
BEGIN
FOR i IN 1 .. l_ids.COUNT LOOP
DBMS_OUTPUT.PUT_LINE(l_ids(i));
END LOOP;
END;
/
DECLARE
TYPE t_num_list IS TABLE OF NUMBER;
l_ids t_num_list := t_num_list(10, 20, 30);
BEGIN
l_ids.DELETE(2);
FOR i IN l_ids.FIRST .. l_ids.LAST LOOP
IF l_ids.EXISTS(i) THEN
DBMS_OUTPUT.PUT_LINE(l_ids(i));
END IF;
END LOOP;
END;
/
FIRST / LASTを使う時の注意
FIRST と LAST は、最初と最後の添字を返す便利なメソッドです。ただし、空のコレクションでは NULL を返すため、そのままループ範囲に使うと別のエラーや意図しない動きにつながります。
DECLARE
TYPE t_num_list IS TABLE OF NUMBER;
l_ids t_num_list := t_num_list();
BEGIN
IF l_ids.COUNT > 0 THEN
FOR i IN l_ids.FIRST .. l_ids.LAST LOOP
IF l_ids.EXISTS(i) THEN
DBMS_OUTPUT.PUT_LINE(l_ids(i));
END IF;
END LOOP;
END IF;
END;
/
Oracle公式のコレクションメソッド説明でも、COUNT、FIRST、LAST、EXTEND などはコレクションの状態確認と操作に使うメソッドとして整理されています。
BULK COLLECTで0件だった場合
BULK COLLECT で取得したコレクションは、0件のことがあります。その直後に l_rows(1) を読むとORA-06533になりやすいので、必ず COUNT を確認します。大量データ処理は BULK COLLECT / FORALL完全ガイド も参考になります。
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 を使う場合は、明示的カーソル完全ガイド のように、取得件数ごとの処理終了条件を明確にします。
FORALLで添字がずれる場合
FORALL では、ループ範囲とコレクションの実在する添字が合っていないと、添字関連のエラーにつながります。削除済み要素や疎なコレクションを扱う場合は、INDICES OF や VALUES OF の利用を検討します。
DECLARE
TYPE t_num_list IS TABLE OF NUMBER;
l_ids t_num_list := t_num_list(10, 20, 30);
BEGIN
l_ids.DELETE(2);
FORALL i IN INDICES OF l_ids
INSERT INTO work_ids(id) VALUES (l_ids(i));
END;
/
大量DMLでは、単に 1 .. l_ids.COUNT と書くより、実在する添字を対象にする方が安全な場面があります。FORALL と例外処理は BULK COLLECT / FORALL完全ガイド と合わせて確認してください。
VARRAYで出る場合
VARRAYでは、現在の要素数を超える添字に代入するとORA-06533になります。また、最大要素数を超えて増やそうとする場合は別の添字関連エラーになることがあります。COUNT と LIMIT の両方を見ます。
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('COUNT=' || l_codes.COUNT || ', LIMIT=' || l_codes.LIMIT);
END;
/
DELETE後の穴あきコレクション
ネスト表では DELETE によって途中の要素が欠けることがあります。COUNT は要素数、LAST は最後の添字なので、必ずしも同じ値とは限りません。穴あきの可能性がある場合は EXISTS を使います。
DECLARE
TYPE t_num_list IS TABLE OF NUMBER;
l_ids t_num_list := t_num_list(10, 20, 30);
BEGIN
l_ids.DELETE(2);
DBMS_OUTPUT.PUT_LINE('COUNT=' || l_ids.COUNT); -- 2
DBMS_OUTPUT.PUT_LINE('LAST=' || l_ids.LAST); -- 3
IF l_ids.EXISTS(2) THEN
DBMS_OUTPUT.PUT_LINE(l_ids(2));
END IF;
END;
/
調査手順
実際にORA-06533が出たら、ORA-06512の行番号から、USER_SOURCE でどの添字を参照しているかを確認します。その行の直前で COUNT、EXTEND、DELETE、BULK COLLECT の結果を見ます。
SELECT line,
text
FROM user_source
WHERE name = 'PKG_ORDER'
AND type = 'PACKAGE BODY'
AND line BETWEEN 80 AND 100
ORDER BY line;
| 順番 | 見る場所 | 確認内容 |
|---|---|---|
| 1 | ORA-06512の最初のオブジェクト付き行 | どのソース行で添字参照したか |
| 2 | 参照している添字 | i や固定値がCOUNT以内か |
| 3 | 直前のEXTEND |
要素を増やしてから代入しているか |
| 4 | BULK COLLECT結果 |
0件時の防御があるか |
| 5 | DELETEの有無 |
穴あきにEXISTSで対応しているか |
よくある原因と対処一覧
| 原因 | 症状 | 対処 |
|---|---|---|
EXTENDせずに代入 |
l_list(1) := valueで失敗 |
先にEXTEND |
| 0件なのに1件目を読む | BULK COLLECT後にl_list(1)で失敗 |
COUNT > 0を確認 |
| ループ範囲がずれている | 1 .. n のnがCOUNTより大きい |
1 .. l_list.COUNTにする |
| DELETEで穴あき | FIRST .. LAST内で欠番を読む |
EXISTS(i)を確認 |
| VARRAYの件数不足 | 現在件数を超えた添字へ代入 | COUNTとLIMITを確認 |
チェックリスト
| 項目 | OKの状態 |
|---|---|
| コレクションを初期化した | ORA-06531ではない状態になっている |
| 代入前にEXTENDした | 代入先の添字が存在している |
| 読み取り前にCOUNTを見た | 0件時に要素参照していない |
| 穴あきならEXISTSを見た | DELETE後の欠番を読んでいない |
| BULK COLLECT後の0件を処理した | 取得0件でも落ちない |
| ORA-06512の行を確認した | 発生行と呼び出し元を分けている |
よくある質問
初期化しているのにORA-06533になります
初期化はできていても、要素数が足りない可能性があります。COUNT を確認し、代入前に EXTEND してください。
ORA-06531との違いは何ですか?
ORA-06531はコレクション自体がNULL、ORA-06533は初期化済みだが添字が要素数を超えている状態です。
FIRST .. LASTでループしているのに落ちます
DELETEで穴あきになっている可能性があります。ループ内で EXISTS(i) を確認してください。
BULK COLLECTで0件の時はどうすればよいですか?
COUNT > 0 を確認してから1件目を参照します。0件なら処理をスキップするか、空結果として扱います。
まとめ
ORA-06533は、PL/SQLコレクションの要素数を超えて添字参照した時に発生します。未初期化のORA-06531とは違い、コレクション自体は初期化済みで、要素数や添字の扱いに問題がある状態です。
対処は、要素追加前に EXTEND する、読み取り前に COUNT を確認する、穴あきコレクションでは EXISTS を使う、BULK COLLECT の0件を考慮する、という流れです。ORA-06512の行番号から実際に範囲外参照している箇所を確認すると、修正箇所を絞り込みやすくなります。
参考
ORA-06533 – Oracle Database Error Help
Collection Methods – Oracle Database PL/SQL Language Reference
PL/SQL Collections and Records – Oracle Database PL/SQL Language Reference

