2012-09-13 4 views
13

私はテーブル列の行タイプのタイプによって作成された連想配列を持っています。PL/SQLでNULL結合配列がチェックされていないのはなぜですか?

例を与えることは、これは(テーブル名が異なっているが、構造は同じである)である方法です:

これは、テーブルの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; 

私はこの が「ヌル連想配列」の結果が印刷されている必要がありますと仮定します。ただし、条件が失敗し、else部分にジャンプします。 PL/SQL:私はコレクションは

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を参照し、例外を発生させます:数値または値のエラー

NULL結合配列のためです。 NULL結合配列のためにエラーが発生していますか?

なぜ最初のチェックが失敗するのですか?私は間違って何をしていますか?

データベース・サーバーは、Oracleの11グラムEE(バージョン11.2.0.3.0 64ビット)

+0

私はしばらくPLSQLをしますが、あなたのforループ内( 'DBMS_OUTPUT.PUT_LINE(していない「のemp名:」 Emp(i).name); ')は' Emp(i).name'を 'emp(i).name'とすべきですか? –

+0

@jschoen変数名は大文字と小文字を区別しないので、意味はありません。 – Sathya

答えて

12

私は、これが印刷されている「ヌル連想配列」になるはずであると仮定します。連想配列では、その前提が間違っています。彼らは宣言されても存在しますが、空です。これは、PL/SQLコレクションの他のタイプのために正しいことになります。

あなたがそれを初期化するまでは、ネストされたテーブルまたはVARRAYがアトミックNULLです。 コレクション自体は、その要素ではなくヌルです。 ネストした表またはVARRAYを初期化するには、コレクション型と同じ名前のシステム定義の ファンクションのコンストラクタを使用します。この関数 は、渡された要素からコレクションを構築します。

各VARRAYおよび入れ子になった テーブル変数に対して、コンストラクターを明示的に呼び出す必要があります。連想配列、コレクションの3番目の種類は、 コンストラクタを使用しません。コンストラクタの呼び出しは、関数 の呼び出しが許可されている場所であれば許可されます。 Initializing and Referencing Collections

は比較:正しく行わ

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ですのでORA-06502: PL/SQL: Numeric or value errorで、なぜあなたの第二の例の結果である、NULLです。

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また、連想配列はスパースである可能性があることにも注意してください。 firstlastの間の数値をループすると、まばらなコレクションの例外が発生します。代わりに、そのようfirstnextを使用します(ループへLastprev他の方向を。)

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. 
+0

が明らかになりました。詳細な答えをありがとう! – Sathya

+2

これは正解です。しかし、私にとっては、Oracleの奇妙なことを時々強調しています。確かに、可変サイズの配列(PLSQLの "table")の全体のポイントは、実行時にいくつのレコードがあるかをあらかじめ知っていないということです(つまり、 。そして、配列の使用の全ポイントは、あなたがそれらにループすることができるように!!です。したがって、ループする前にリストの長さがゼロでないことをチェックしなければならないのは完全に直感的なことです。標準の暗黙的なカーソルと同じように、パーサーが単にゼロ回ループするのはなぜですか? – cartbeforehorse

5

は私が最初のチェックが失敗している理由をお答えするつもりはないです。私はそのようなことをやろうとは考えておらず、間違いを起こさないことに非常に驚いています。

ループで例外が発生するのは、前述のように、インデックスemp.firstが存在しないためです。

nullをチェックするのではなく、実際にこのインデックスの存在を確認する必要があります。あなたはどちら.exists(i)構文を使用して行うことができます。

if not emp.exists(emp.first) then 
    dbms_output.put_line('Nothing in here.'); 
end if; 
+0

Ben、Oracleのマニュアルには「連想配列でEXISTSを使用することはできません。 - http://docs.oracle.com/cd/B28359_01/appdev.111/b28370/collections.htm#CJAEFFIDによると、プログラム単位は正常に実行されます。 Hrm。 – Sathya

+0

はい@サティヤ、ごめんなさい、あなたがテーブルの行タイプからやっているという事実を忘れてしまった。それは正常に実行されますか?それは私のために失敗している?これがカーソルの行タイプであれば動作します。 – Ben

+0

はい、私はそれを編集したように、それ以外の場合はドキュメントにもかかわらず、奇妙にも十分に実行されます – Sathya