テーブル列のrowtypeのタイプによって作成された連想配列があります。
例を挙げると、次のようになります(テーブル名は異なりますが、構造は同じです)。
これはテーブルのDDLです
CREATE TABLE employees
(
id NUMBER,
name VARCHAR2(240),
salary NUMBER
);
これが私の手順が行っていることです:
DECLARE
TYPE table_of_emp
IS TABLE OF employees%ROWTYPE INDEX BY BINARY_INTEGER;
emp TABLE_OF_EMP;
BEGIN
IF emp IS NULL THEN
dbms_output.Put_line('Null associative array');
ELSE
dbms_output.Put_line('Not null');
END IF;
END;
これはshould結果として「Null連想配列」が出力されると思います。ただし、if
条件は失敗し、実行はelse部分にジャンプします。
ここで、コレクション値を出力するためにfor
ループを挿入すると
DECLARE
TYPE table_of_emp
IS TABLE OF employees%ROWTYPE INDEX BY BINARY_INTEGER;
emp TABLE_OF_EMP;
BEGIN
IF emp IS NULL THEN
dbms_output.Put_line('Null associative array');
ELSE
dbms_output.Put_line('Not null');
FOR i IN emp.first..emp.last LOOP
dbms_output.Put_line('Emp name: '
|| Emp(i).name);
END LOOP;
END IF;
END;
次に、プログラムユニットは、forループ行を参照して例外を発生させます。
ORA-06502:PL/SQL:数値または値のエラー
これは、nullの連想配列が原因であると私は推測します。 null連想配列が原因でエラーが発生していますか?
では、なぜ最初のチェックが失敗するのでしょうか。私は何が間違っているのですか?
データベースサーバーはOracle11g EE(バージョン11.2.0.3.0 64ビット)です。
これにより「Null連想配列」が出力されるはずだと思います。この仮定は連想配列では間違っています。それらは宣言されたときに存在しますが、空です。他のタイプのPL/SQLコレクションの場合は正しいでしょう。
初期化するまで、ネストされたテーブルまたはvarrayはアトミックにnullです。コレクション自体はnullであり、その要素ではありません。ネストされたテーブルまたはVARRAYを初期化するには、コレクションタイプと同じ名前のシステム定義関数であるコンストラクターを使用します。この関数は、渡された要素からコレクションを構築します。
各VARRAYおよびネストされたテーブル変数のコンストラクターを明示的に呼び出す必要があります。 3番目の種類のコレクションである連想配列は、コンストラクターを使用しません。コンストラクター呼び出しは、関数呼び出しが許可されている場所であればどこでも許可されます。 コレクションの初期化と参照
比較:
SQL> declare
2 type varchar2_100_aa is table of varchar2(100) index by binary_integer;
3 test varchar2_100_aa;
4 begin
5 test(1) := 'Hello';
6 dbms_output.put_line(test(1));
7 end;
8 /
Hello
PL/SQL procedure successfully completed.
SQL> declare
2 type varchar2_100_va is varray(100) of varchar2(100);
3 test varchar2_100_va;
4 begin
5 test(1) := 'Hello';
6 dbms_output.put_line(test(1));
7 end;
8 /
declare
*
ERROR at line 1:
ORA-06531: Reference to uninitialized collection
ORA-06512: at line 5
変数配列が正しく実行されました:
SQL> declare
2 type varchar2_100_va is varray(10) of varchar2(100);
3 test varchar2_100_va;
4 begin
5 test := varchar2_100_va(); -- not needed on associative array
6 test.extend; -- not needed on associative array
7 test(1) := 'Hello';
8 dbms_output.put_line(test(1));
9 end;
10 /
Hello
PL/SQL procedure successfully completed.
連想配列が空であるため、first
とlast
はnullです。これが、2番目の例がORA-06502: PL/SQL: Numeric or value error
になる理由です。
SQL> declare
2 type varchar2_100_aa is table of varchar2(100) index by binary_integer;
3 test varchar2_100_aa;
4 begin
5 dbms_output.put_line(test.count);
6 dbms_output.put_line(coalesce(to_char(test.first), 'NULL'));
7 dbms_output.put_line(coalesce(to_char(test.last), 'NULL'));
8 test(1) := 'Hello';
9 dbms_output.new_line;
10 dbms_output.put_line(test.count);
11 dbms_output.put_line(coalesce(to_char(test.first), 'NULL'));
12 dbms_output.put_line(coalesce(to_char(test.last), 'NULL'));
13 end;
14 /
0
NULL
NULL
1
1
1
PL/SQL procedure successfully completed.
[〜#〜] edit [〜#〜]連想配列はスパースである可能性があることにも注意してください。 first
とlast
の間の数値をループすると、まばらなコレクションに対して例外が発生します。代わりに、first
と next
を次のように使用します:(Last
とprev
を使用して、反対方向をループします。)
SQL> declare
2 type varchar2_100_aa is table of varchar2(100) index by binary_integer;
3 test varchar2_100_aa;
4 i binary_integer;
5 begin
6 test(1) := 'Hello';
7 test(100) := 'Good bye';
8 dbms_output.put_line(test.count);
9 dbms_output.put_line(coalesce(to_char(test.first), 'NULL'));
10 dbms_output.put_line(coalesce(to_char(test.last), 'NULL'));
11 dbms_output.new_line;
12 --
13 i := test.first;
14 while (i is not null) loop
15 dbms_output.put_line(to_char(i, '999') || ' - ' || test(i));
16 i := test.next(i);
17 end loop;
18 end;
19 /
2
1
100
1 - Hello
100 - Good bye
PL/SQL procedure successfully completed.
最初のチェックが失敗する理由についてはお答えしません。私はそのようなことをすることを考えたことがなく、それがエラーを引き起こさないことに非常に驚いています。
ループで例外が発生する理由は、ご指摘のとおり、インデックス_emp.first
_が存在しないためです。
Nullをチェックするのではなく、実際にこのインデックスの存在をチェックする必要があります。 .exists(i)
構文を使用して実行できること:
_if not emp.exists(emp.first) then
dbms_output.put_line('Nothing in here.');
end if;
_