oracle-databaseplsqlbulk-operations

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


I am learning PL/SQL. I have written the procedure below using cursor and nested table to display employee names.

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;

It compilesd without any errors. When I am executing the procedure, I am able to display all the employees names. But, the below error is thrown before displaying data. Can anyone please help me out of this?

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.

Thanks in advance.


Solution

  • Your output suggests you have not enabled DBMS_OUTPUT. With set serveroutput on it becomes obvious that the error is thrown once all the employees have been processed (I added a row count to the display):

    #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> 
    

    So, why is this happening? It's because you're using the wrong test after the FETCH. SQL%NOTFOUND is a test for SQL statements embedded in PL/SQL. A FETCH from an Explicit Cursor is not a SQL operation.

    SQL%NOTFOUND is never true after a FETCH, which means the EXIT WHEN condition is never met. Hence, the program continues to loop after all the records have been fetched. The program hurled ORA-06502 because emp_data.last is null after all the records have been fetched, so the LOOP test blows up.

    The best solution is to test for the number of rows returned into the array:

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

    With this one change your procedure will run:

    #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>
    

    Note that you should not use exit when c1%notfound; . Although that is correct syntax for testing whether an Explicit Cursor returns a result, its behaviour is different (and non-intuitive) with bulk operations. Then, the test is only true when the FETCH returns the exact number of rows specified in the LIMIT clause. In your scenario it means you lose the last seven records:

    #98employee name is : Kevin
    #99employee name is : Donald
    #100employee name is : Douglas
    
    PL/SQL procedure successfully completed.
    
    SQL>
    

    Incidentally, casting FIRST_DATE is unnecessary because (assuming you are using the standard HR schema) it's already a string. We need to use to_char() for things like numbers or dates, so we can control the formatting.