2

PL/SQLを学んでいます。従業員名を表示するために、カーソルとネストされたテーブルを使用して以下の手順を記述しました。

create or replace procedure
  employees_data
is
  cursor c1 is select * from employees;
  type empl_tbl is table of c1%rowtype;
  emp_data empl_tbl;
begin
  open c1; 
    LOOP
    fetch c1 bulk collect into emp_data limit 100;
    exit when sql%notfound;
    for i in 1..emp_data.last
      loop
      dbms_output.put_line ('employee name is : ' || to_char(emp_data(i).first_name));
    end loop;
    end loop;
    close c1;
end employees_data;

エラーなしでコンパイルされます。手順を実行すると、すべての従業員の名前を表示できます。ただし、データを表示する前に以下のエラーがスローされます。誰でも私を助けてくれますか?

Error starting at line : 1 in command -
exec employees_data()
Error report -
ORA-06502: PL/SQL: numeric or value error
ORA-06512: at "HR.EMPLOYEES_DATA", line 12
ORA-06512: at line 1
06502. 00000 -  "PL/SQL: numeric or value error%s"
*Cause:    An arithmetic, numeric, string, conversion, or constraint error
           occurred. For example, this error occurs if an attempt is made to
           assign the value NULL to a variable declared NOT NULL, or if an
           attempt is made to assign an integer larger than 99 to a variable
           declared NUMBER(2).
*Action:   Change the data, how it is manipulated, or how it is declared so
           that values do not violate constraints.

前もって感謝します。

4

1 に答える 1

2

出力は、DBMS_OUTPUT を有効にしていないことを示しています。set serveroutput onすべての従業員が処理されると、エラーがスローされることが明らかになります (表示に行数を追加しました) 。

#100:employee name is : Douglas
#1:employee name is : Jennifer
#2:employee name is : Michael
#3:employee name is : Pat
#4:employee name is : Susan
#5:employee name is : Hermann
#6:employee name is : Shelley
#7:employee name is : William
BEGIN employees_data; END;

*
ERROR at line 1:
ORA-06502: PL/SQL: numeric or value error
ORA-06512: at "HR.EMPLOYEES_DATA", line 12
ORA-06512: at line 1


SQL> 

それで、なぜこれが起こっているのですか?FETCH の後に間違ったテストを使用しているためです。 SQL%NOTFOUNDPL/SQLに埋め込まれたSQL文のテストです。Explicit Cursor からの FETCH は SQL 操作ではありません。

SQL%NOTFOUNDFETCH の後は決して true になりません。つまり、EXIT WHEN 条件が満たされないことを意味します。したがって、すべてのレコードがフェッチされた後、プログラムはループし続けます。プログラムは、すべてのレコードがフェッチされた後に null であるため、スローされたため、LOOP テストが爆発しますORA-06502emp_data.last

最善の解決策は、配列に返される行数をテストすることです。

fetch c1 bulk collect into emp_data limit 100;
exit when emp_data.count()=0;

この 1 つの変更で、プロシージャが実行されます。

#100:employee name is : Douglas
#1:employee name is : Jennifer
#2:employee name is : Michael
#3:employee name is : Pat
#4:employee name is : Susan
#5:employee name is : Hermann
#6:employee name is : Shelley
#7:employee name is : William

PL/SQL procedure successfully completed.

SQL>

を使用しないでくださいexit when c1%notfound;。Explicit Cursor が結果を返すかどうかをテストするための正しい構文ですが、一括操作ではその動作が異なります (そして直感的ではありません)。次に、FETCH がLIMIT 句で指定された正確な数の行を返す場合にのみ、テストは true になります。あなたのシナリオでは、最後の 7 つのレコードを失うことを意味します。

#98employee name is : Kevin
#99employee name is : Donald
#100employee name is : Douglas

PL/SQL procedure successfully completed.

SQL>

ちなみに、(標準の HR スキーマを使用していると仮定して) FIRST_DATE は既に文字列であるため、キャストする必要はありません。to_char()フォーマットを制御できるように、数値や日付などに使用する必要があります。

于 2015-08-31T12:29:24.917 に答える