Oracle INVALID_NUMBER exception in my function does not work - oracle

The Oracle function below assign 'A' to number variable.
But the Exception clause does not catch INVALID_NUMBER system exception.
CREATE OR REPLACE FUNCTION TEST2
(P1 IN VARCHAR2)
RETURN NUMBER AS V_VALUE NUMBER;
BEGIN
SELECT(
--SELECT 1/TO_NUMBER(P1)
SELECT 'A'
FROM DUAL
)
INTO V_VALUE
FROM DUAL;
RETURN V_VALUE;
EXCEPTION
WHEN INVALID_NUMBER THEN -- If I change INVALID_NUMBER to OTHERS, then it works.
RETURN -1;
END;
/
SELECT TEST2('1') FROM DUAL;
When I change INVALID_NUMBER to OTHERS, then it works.
How to modify above code to chatch the INVALID_NUMBER exception?

Because you get VALUE_ERROR when ORA-06502 raised as occurs in your case. So, replace INVALID_NUMBER with VALUE_ERROR.
as an example; if the SELECT statement was :
SELECT 5
INTO V_VALUE
FROM DUAL
WHERE TO_NUMBER('A')=1;
you'd get INVALID_NUMBER(ORA-01722) exception.

Some more info (to what Barbaros already told you).
The INVALID_NUMBER Exception (ORA-01722) occurs in a SQL statement when the conversion of a character string into a number fails because the string does not represent a valid number. (In procedural statements, VALUE_ERROR is raised.) This exception is also raised when the LIMIT-clause expression in a bulk FETCH statement does not evaluate to a positive number.
Compare
SQL> select 'a'/2 from dual;
select 'a'/2 from dual
*
ERROR at line 1:
ORA-01722: invalid number
to
SQL> declare
2 l_num number;
3 begin
4 l_num := 'a' / 2;
5 end;
6 /
declare
*
ERROR at line 1:
ORA-06502: PL/SQL: numeric or value error: character to number conversion error
ORA-06512: at line 4
to
SQL> declare
2 l_num number;
3 begin
4 select 'a' / 2 into l_num from dual;
5 end;
6 /
declare
*
ERROR at line 1:
ORA-01722: invalid number
ORA-06512: at line 4
Isn't that nice of Oracle? More or less the same thing, but different response.

Related

ORACLE PL/SQL : How to pass an exception into a procedure

Is there a way to pass exception into a procedure to call "raise" after doing some actions to process exception. So that the outer code block will get the exact exception that was raised
Something like this:
begin
...
exception
when others then
error_handler( err );
end;
procedure error_handler ( err ) is
begin
/*
here some code to handle and log the exception...
*/
raise err;
end;
Or the only way is to pass SQLCODE and SQLERRM into the procedure and later call raise_application_error( SQLCODE, SQLERRM )?
If I understood you correctly, this is what you're asking.
Sample log table:
SQL> create table err_log
2 (program varchar2(30),
3 datum date,
4 sqlcode number
5 );
Table created.
Logging procedure should be an autonomous transaction so that you could commit in it, without affecting main transaction.
SQL> create or replace procedure error_handler
2 (p_program in varchar2, p_sqlcode in number)
3 is
4 pragma autonomous_transaction;
5 begin
6 insert into err_log (program, datum, sqlcode)
7 values (p_program, sysdate, p_sqlcode);
8 commit;
9 end;
10 /
Procedure created.
Another procedure (whose execution you're logging); it'll raise division by zero. See lines #8 and #9 which call the logging procedure and then just re-raise the error:
SQL> create or replace procedure p_test is
2 l_program varchar2(30) := 'P_TEST';
3 l_value number;
4 begin
5 l_value := 1 / 0;
6 exception
7 when others then
8 error_handler(l_program, sqlcode);
9 raise;
10 end p_test;
11 /
Procedure created.
OK, everything is set. Let's try it:
SQL> exec p_test;
BEGIN p_test; END;
*
ERROR at line 1:
ORA-01476: divisor is equal to zero --> this is result of RAISE in line #9
ORA-06512: at "SCOTT.P_TEST", line 9
ORA-06512: at "SCOTT.P_TEST", line 5
ORA-06512: at line 1
Log table contents:
SQL> select * from err_log;
PROGRAM DATUM SQLCODE
------------------------------ ------------------- ----------
P_TEST 01.11.2022 11:13:31 -1476
SQL>
You asked, literally:
How to pass an exception into a procedure?
You can't, as far as I can tell:
SQL> create or replace procedure error_handler_text
2 (p_err in exception) --> if this is what you asked
3 is
4 begin
5 null;
6 end;
7 /
Warning: Procedure created with compilation errors.
SQL> show err
Errors for PROCEDURE ERROR_HANDLER_TEXT:
LINE/COL ERROR
-------- -----------------------------------------------------------------
2/13 PLS-00103: Encountered the symbol "EXCEPTION" when expecting one
of the following:
out <an identifier> <a double-quoted delimited-identifier>
table columns long double ref char standard time timestamp
interval date binary national character nchar
The symbol "<an identifier> was inserted before "EXCEPTION" to
continue.
SQL>

Is there any way to assign a select query to local variable in PL/SQL other than select into statement?

Is there any way to assign a select query to local variable in PL/SQL other than select into statement?. Because select into throwing null value exception if the select query returns null value. Thanks
It would be helpful to post your code, but here is an example that should show the behavior you need. Assume there is a table called courses_tbl:
declare
cnumber number := NULL;
CURSOR c1
IS
SELECT course_number
FROM courses_tbl
WHERE course_name = 'XYZ';
BEGIN
open c1;
fetch c1 into cnumber;
if c1%notfound then
-- Do something here if you care about not found.
cnumber := 999; -- whatever
end if;
you can read about cursor attributes here
Seems that you need to use the exception handling as follows:
... -- Your procedure other code
BEGIN
SELECT <COLUMN_NAME> INTO <YOUR_VARIABLE>
FROM .....
WHERE ....
EXCEPTION WHEN NO DATA FOUND THEN
<YOUR_VARIABLE> := NULL;
END;
... -- Your procedure other code
You can use EXECUTE IMMEDIATE...INTO...:
DECLARE
nCnumber NUMBER;
BEGIN
EXECUTE IMMEDIATE 'SELECT CNUMBER FROM COURSES_TBL WHERE CNUMBER = 1'
INTO nCnumber;
DBMS_OUTPUT.PUT_LINE('SELECT #1 : nCnumber = ' || nCnumber);
nCnumber := NULL;
BEGIN
EXECUTE IMMEDIATE 'SELECT CNUMBER FROM COURSES_TBL WHERE CNUMBER = 100'
INTO nCnumber;
DBMS_OUTPUT.PUT_LINE('SELECT #2 : nCnumber = ' || nCnumber);
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('SELECT #2 : NO DATA FOUND');
END;
END;
db<>fiddle here
You've seen how to do it using a cursor or exception handling section (which is - in my opinion - the right way to do it). However, as we're discussing, here's yet another option - an aggregate function. It won't return NO_DATA_FOUND but NULL.
This is what you have now:
SQL> declare
2 l_job emp.job%type;
3 begin
4 select job
5 into l_job
6 from emp
7 where ename = 'Does not exist';
8 end;
9 /
declare
*
ERROR at line 1:
ORA-01403: no data found
ORA-06512: at line 4
This is what you might do:
SQL> declare
2 l_job emp.job%type;
3 begin
4 select max(job)
5 into l_job
6 from emp
7 where ename = 'Does not exist';
8 end;
9 /
PL/SQL procedure successfully completed.
SQL>

Procedure calling gone bad - Statement Ignored

I have the following procedure to insert users in a table:
CREATE OR REPLACE PROCEDURE ELR_ADD_USER
(I_NAME IN VARCHAR2,
I_MORADA IN VARCHAR2,
I_BIRTHDATE IN DATE,
I_COUNTRY IN VARCHAR2,
O_ID OUT NUMBER,
O_ERROR_MSG OUT VARCHAR2)
IS
ERROR_NULL EXCEPTION;
BEGIN
IF I_NAME IS NULL OR
I_MORADA IS NULL OR
I_BIRTHDATE IS NULL OR
I_COUNTRY IS NULL THEN
RAISE ERROR_NULL;
END IF;
O_ID := ELR_seq_USER_ID.nextval;
IF O_ID IS NULL
RAISE ERROR_NULL;
END IF;
INSERT INTO ELR_USERS
VALUES (O_ID, I_NOME, I_MORADA, I_BIRTHDATE, I_COUNTRY);
EXCEPTION
WHEN ERROR_NULL THEN
O_ERROR_MSG := 'NULL FIELDS';
WHEN OTHERS THEN
O_ERROR_MSG := 'UNEXPECTED ERROR: '|| sqlerrm;
END;
/
I think the procedure and it's syntax are correct. However when I'm trying to call it with:
DECLARE
P_NAME VARCHAR2(50);
P_MORADA VARCHAR2(50);
P_BIRTHDATE DATE;
P_COUNTRY VARCHAR2(20);
P_ID NUMBER(20);
P_ERROR_MSG VARCHAR2(4000);
BEGIN
ELR_ADD_USER('ED WARNER','CENAS Street',SYSDATE,
'China', P_ID, P_ERROR_MSG);
IF P_ERROR_MSG IS NOT NULL THEN
DBMS_OUTPUT.PUT_LINE('ERROR: '||P_ERROR_MSG);
END IF;
END;
/
I get the following message:
Is there something wrong with the calling or the procedure itself?
ORA-06550 followed by PLS-00905 is clearly a compilation error. The procedure is in INVALID state.
Recompile the procedure, and use SHOW ERRORS to get the complete error details.
SHOW ERROR PROCEDURE RMS_MM.ELR_ADD_USER or simply SHOW ERRORS
For example,
SQL> CREATE OR REPLACE PROCEDURE TestProc
2 AS
3 vnum number;
4 BEGIN
5 vnum := vAnotherNum;
6 END;
7 /
Warning: Procedure created with compilation errors.
SQL> execute TestProc();
BEGIN TestProc(); END;
*
ERROR at line 1:
ORA-06550: line 1, column 7:
PLS-00905: object EXAMPLE.TESTPROC is invalid
ORA-06550: line 1, column 7:
PL/SQL: Statement ignored
SQL> show error procedure TestProc;
Errors for PROCEDURE TESTPROC:
LINE/COL ERROR
-------- -----------------------------------------------------------------
5/1 PL/SQL: Statement ignored
5/9 PLS-00201: identifier 'VANOTHERNUM' must be declared

Missing keyword error in Oracle anonymous PL/SQL block

An anonymous PL/SQL block:
DECLARE
CURSOR employees_in_10_cur
IS
SELECT *
FROM ad_week_table
BEGIN
FOR employee_rec
IN employees_in_10_cur
LOOP
DBMS_OUTPUT.put_line(employee_rec.ad_no || ',' || employee_rec.week_no);
END LOOP;
END;
I get a missing keyword error when I execute this block. What am I doing wrong?
put a semi-colon after defining cursor query;
DECLARE
CURSOR employees_in_10_cur
IS
SELECT *
FROM ad_week_table;
BEGIN
FOR employee_rec
IN employees_in_10_cur
LOOP
DBMS_OUTPUT.put_line (
employee_rec.ad_no || ',' || employee_rec.week_no );
END LOOP;
END;
You're missing a semi-colon at the end of your cursor:
CURSOR employees_in_10_cur
IS
SELECT *
FROM ad_week_table;
The error message will always give you the line number of the error occurring. Please always check this and look in that area.
For instance; if I change the table so I can run this I get the following:
SQL> declare
2
3 cursor employees_in_10_cur is
4 select *
5 from user_tables
6
7 begin
8 for employee_rec in employees_in_10_cur loop
9 dbms_output.put_line (
10 employee_rec.ad_no || ',' || employee_rec.week_no );
11 end loop;
12 end;
13 /
for employee_rec in employees_in_10_cur loop
*
ERROR at line 8:
ORA-06550: line 8, column 8:
PL/SQL: ORA-00905: missing keyword
ORA-06550: line 4, column 5:
PL/SQL: SQL Statement ignored
ORA-06550: line 11, column 4:
PLS-00103: Encountered the symbol "END" when expecting one of the following:
begin function pragma procedure subtype type <an identifier>
<a double-quoted delimited-identifier> current cursor delete
exists prior
You have 3 errors; one at line 8 because the cursor is invalid, one at line 11 because the loop doesn't happen because the cursor is invalid and one at line 4, which says "statement ignored".

Oracle PL/SQL: syntax error when using a variable within SAMPLE clause

The following PL/SQL block works:
DECLARE
r TABLE1%ROWTYPE;
BEGIN
SELECT * INTO r FROM TABLE1 SAMPLE(1) WHERE ROWNUM = 1;
END;
However, when I try to replace the literal with a variable within the SAMPLE clause, Oracle returns a syntax error:
DECLARE
s NUMBER;
r TABLE1%ROWTYPE;
BEGIN
s := 1;
SELECT * INTO r FROM TABLE1 SAMPLE(s) WHERE ROWNUM = 1;
END;
ORA-06550: line 6, column 39:
PL/SQL: ORA-00933: SQL command not properly ended
What am I doing wrong?
I'm using Oracle 10 and SQL Developer.
(These are simplified examples. What I'm actually trying to do in practice is to optimize the selection of random row, where SAMPLE percentage would be calculated dynamically, based on the current number of rows in the table. So I can't use literal, I need a variable to assign the result of the calculation.)
The SAMPLE synthax requires a numeral. You could use dynamic SQL to build a dynamic query, for example with a ref cursor:
SQL> CREATE TABLE table1 AS
2 SELECT ROWNUM ID, rpad(ROWNUM, 10, 'x') DATA
3 FROM dual CONNECT BY LEVEL <= 1000;
Table created
SQL> DECLARE
2 l_cur SYS_REFCURSOR;
3 l_row table1%ROWTYPE;
4 l_pct NUMBER := 50;
5 BEGIN
6 OPEN l_cur
7 FOR 'SELECT * FROM table1 SAMPLE('||l_pct||') WHERE rownum = 1';
8 LOOP
9 FETCH l_cur INTO l_row;
10 EXIT WHEN l_cur%NOTFOUND;
11 dbms_output.put_line(l_row.id);
12 END LOOP;
13 END;
14 /
3
PL/SQL procedure successfully completed

Resources