错误 - ORA-06502: PL/SQL: 数字或值错误

Error - ORA-06502: PL/SQL: numeric or value error

我正在学习PL/SQL。我已经使用光标和嵌套 table 编写了下面的程序来显示员工姓名。

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.

提前致谢。

您的输出表明您尚未启用 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%NOTFOUND 是对 PL/SQL 中嵌入的 SQL 语句的测试。来自显式游标的 FETCH 不是 SQL 操作。

SQL%NOTFOUND 在 FETCH 之后永远不会为真,这意味着永远不会满足 EXIT WHEN 条件。因此,程序在获取所有记录后继续循环。程序抛出 ORA-06502 因为 emp_data.last 在获取所有记录后为 null,因此 LOOP 测试失败。

最佳解决方案是测试返回到数组中的行数:

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

通过这一更改,您的程序将 运行:

#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 returns 是否为结果的正确语法,但它的行为与批量操作不同(并且不直观)。然后,只有当 FETCH returns LIMIT 子句中指定的确切行数 时,测试才成立。在您的场景中,这意味着您丢失了最后七条记录:

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

PL/SQL procedure successfully completed.

SQL>

顺便说一句,转换 FIRST_DATE 是不必要的,因为(假设您使用的是标准 HR 模式)它已经是一个字符串。我们需要使用 to_char() 来表示数字或日期之类的东西,这样我们就可以控制格式。