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

时间:2015-08-31 11:52:05

标签: oracle plsql bulk-operations

我正在学习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.

提前致谢。

1 个答案:

答案 0 :(得分: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%NOTFOUND是对PL / SQL中嵌入的SQL语句的测试。来自Explicit Cursor的FETCH不是SQL操作。

在FETCH之后,

SQL%NOTFOUND永远不会为真,这意味着永远不会满足EXIT WHEN条件。因此,程序在获取所有记录后继续循环。程序抛出ORA-06502因为emp_data.last在获取所有记录后为空,因此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是否返回结果的正确语法,但它的行为与批量操作不同(并且不直观)。然后,仅当FETCH返回 LIMIT子句中指定的确切行数时,测试才成立。在您的方案中,这意味着您丢失了最后七条记录:

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

PL/SQL procedure successfully completed.

SQL>

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