No_data_found exception is propagating to outer block also? - sql

In my code i am entering the salary which is not available in employees table and then again inserting duplicate employee_id in primary key column of employee table in exception block where i am handling no data found exception but i do not why No data found exception in the end also?
OUTPUT coming:
Enter some other sal
ORA-01400: cannot insert NULL into ("SCOTT"."EMPLOYEES"."LAST_NAME")
ORA-01403: no data found --This should not come according to logic
This is the code:
DECLARE
v_sal number:=&p_sal;
v_num number;
BEGIN
BEGIN
select salary INTO v_num from employees where salary=v_sal;
EXCEPTION
WHEN no_data_found THEN
DBMS_OUTPUT.PUT_LINE('Enter some other sal');
INSERT INTO employees (employee_id)values(100) ;
END;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(sqlerrm);
END;

The behaviour is that errors hurled in the EXCEPTIONS block get concatenated to SQLERRM, and hence propagated upwards. I grant you it is not documented but we can clearly see it here:
SQL> declare
2 v_sal t23.sal%type := 230;
3 l_num t23.sal%type;
4 begin
5 begin
6 begin
7 select sal into l_num
8 from t23 where sal = v_sal;
9 exception
10 when no_data_found then
11 dbms_output.put_line('inner exception::'||sqlerrm);
12 insert into t23 values (99, 'MR KNOX', v_sal);
13 end;
14 exception
15 when dup_val_on_index then
16 dbms_output.put_line('middle exception::'||sqlerrm);
17 insert into t23 (id, sal) values (99, v_sal);
18 end;
19 exception
20 when others then
21 dbms_output.put_line('outer exception::'||sqlerrm);
22 end;
23 /
inner exception::ORA-01403: no data found
middle exception::ORA-00001: unique constraint (APC.T23_PK) violated
ORA-01403: no data found
outer exception::ORA-01400: cannot insert NULL into ("APC"."T23"."LAST_NAME")
ORA-00001: unique constraint (APC.T23_PK) violated
ORA-01403: no data found
PL/SQL procedure successfully completed.
SQL>
Note: if there is a nested exception block which successfully handles the thrown exception it is not concatenated to SQLERRM. That is, the SQLERRM consists of a stack of unsucessfully handled exceptions.

In your exception block you try to insert into employees, but do not set the column last_name, which is not NULL-able.
ORA-01400: cannot insert NULL into ("SCOTT"."EMPLOYEES"."LAST_NAME")
The ORA-01403: no data found is part of the stack-trace, caused by your failed select.
You can either define DEFAULT values for all not-nullable columns or change your insert:
INSERT INTO employees (employee_id, last_name, ...) Values (100, 'Scott', ...);

Related

How to catch the null constraint exception in plsql when inserting a record?

I want to check the null constraint of a column when inserting a record into a table. There, I am trying to insert a null value through a procedure to a column which cannot be null. Here is my procedure.
CREATE OR REPLACE PROCEDURE RecordInsert(s_id IN NUMBER, pid IN NUMBER, pr_id IN NUMBER, quantity NUMBER, rv DATE, exercise_num NUMBER)
IS
null_constraint EXCEPTION;
PRAGMA EXCEPTION_INIT(null_constraint,-1451);
BEGIN
INSERT INTO Supplier_Part_Project_Tab
VALUES(s_id, pid, pr_id_, quantity, rv);
dbms_output.put_line('The row successfully inserted');
COMMIT;
EXCEPTION
WHEN null_constraint THEN
dbms_output.put_line('The column cannot be NULL');
WHEN OTHERS THEN
pkg_Error.prc_Exeception(exercise_num);
END;
This is how I executed the procedure.
BEGIN
RecordInsert( 1002, '', 2001, 80, (TO_DATE('2003/05/03 09:02:44', 'yyyy/mm/dd hh12:mi:ss AM')),8);
COMMIT;
END;
In the above procedure, I am trying to insert pid as null. There, I want to fire the 'null_constraint' exception. But it fires the 'OTHERS' exception. Hope the oracle exception -1451 is correct for my requirement. But why does it not fire?
Sample table:
SQL> CREATE TABLE test
2 (
3 id NUMBER NOT NULL,
4 name VARCHAR2 (20) NOT NULL
5 );
Table created.
Procedure without exception handling section (to see what will happen):
SQL> CREATE OR REPLACE PROCEDURE RecordInsert (par_id IN NUMBER,
2 par_name IN VARCHAR2)
3 IS
4 null_constraint EXCEPTION;
5 PRAGMA EXCEPTION_INIT (null_constraint, -1451);
6 BEGIN
7 INSERT INTO test (id, name)
8 VALUES (par_id, par_name);
9
10 DBMS_OUTPUT.put_line ('The row successfully inserted');
11 /*
12 EXCEPTION
13 WHEN null_constraint
14 THEN
15 DBMS_OUTPUT.put_line ('The column cannot be NULL');
16 WHEN OTHERS
17 THEN
18 DBMS_OUTPUT.put_line ('Others');
19 */
20 END;
21 /
Procedure created.
Testing:
SQL> exec recordinsert(1, 'Littlefoot');
The row successfully inserted
PL/SQL procedure successfully completed.
SQL> exec recordinsert(2, null);
BEGIN recordinsert(2, null); END;
*
ERROR at line 1:
ORA-01400: cannot insert NULL into ("SCOTT"."TEST"."NAME")
ORA-06512: at "SCOTT.RECORDINSERT", line 7
ORA-06512: at line 1
SQL>
Aha. ORA-01400 (not 1451). Let's modify the procedure, then:
SQL> CREATE OR REPLACE PROCEDURE RecordInsert (par_id IN NUMBER,
2 par_name IN VARCHAR2)
3 IS
4 null_constraint EXCEPTION;
5 PRAGMA EXCEPTION_INIT (null_constraint, -1400);
6 BEGIN
7 INSERT INTO test (id, name)
8 VALUES (par_id, par_name);
9
10 DBMS_OUTPUT.put_line ('The row successfully inserted');
11 EXCEPTION
12 WHEN null_constraint
13 THEN
14 DBMS_OUTPUT.put_line ('The column cannot be NULL');
15 WHEN OTHERS
16 THEN
17 DBMS_OUTPUT.put_line ('Others');
18 END;
19 /
Procedure created.
SQL> set serveroutput on
SQL>
SQL> exec recordinsert(2, null);
The column cannot be NULL --> here's your exception
PL/SQL procedure successfully completed.
SQL>
Error code you used was
ORA-01451: column to be modified to NULL cannot be modified to NULL
Cause: The column may already allow NULL values, the NOT NULL constraint is part of a primary key or check constraint, or an ALTER TABLE MODIFY statement attempted to change a column specification unnecessarily, from NULL to NULL.
Action: If a primary key or check constraint is enforcing the NOT NULL constraint, then drop that constraint.
It is related to ALTER TABLE statement, not to inserts which try to insert NULL values into NOT NULL columns, e.g.
SQL> create table test (id number not null, name varchar2(20));
Table created.
SQL> desc test
Name Null? Type
----------------------------------------- -------- ----------------------------
ID NOT NULL NUMBER
NAME VARCHAR2(20)
SQL> alter table test modify name null;
alter table test modify name null
*
ERROR at line 1:
ORA-01451: column to be modified to NULL cannot be modified to NULL
SQL>

How to get rid of compilation error in PL/SQL procedure?

Being new to PL/SQL, I am unable to understand how to manage user-defined exceptions in procedures. My code is giving the Warning 'Procedure created with compilation errors'.
CREATE OR REPLACE PROCEDURE raise_salary
(eid IN employees.e_id%TYPE:=&emp_id,
raise IN employees.salary:=&salary_raise)
IS
cnt INTEGER;
salary employees.salary%TYPE;
BEGIN
SELECT count(*) INTO cnt FROM employees WHERE e_id=eid;
IF cnt=0 THEN
RAISE INVALID_ID;
ELSE
SELECT salary INTO sal FROM employees WHERE e_id=eid;
IF sal IS NULL THEN
RAISE NULL_VALUE;
ELSE
UPDATE employees SET salary=salary+raise WHERE e_id=eid;
dbms_output.put_line('Salary raised!');
END IF;
END IF;
EXCEPTION
WHEN INVALID_ID THEN
dbms_output.put_line('User ID does not exist!');
WHEN NULL_VALUE THEN
dbms_output.put_line('Salary is null in table!');
WHEN others THEN
dbms_output.put_line('Error!');
END;
/
An example:
SQL> CREATE OR REPLACE PROCEDURE testException
2 IS
3 BEGIN
4 raise INVALID_ID;
5 EXCEPTION
6 WHEN INVALID_ID THEN
7 dbms_output.put_line('Invalid ID');
8 END;
9 /
Warning: Procedure created with compilation errors.
A way to know the errors:
SQL> sho err
Errors for PROCEDURE TESTEXCEPTION:
LINE/COL ERROR
-------- -----------------------------------------------------------------
0/0 PL/SQL: Compilation unit analysis terminated
4/5 PL/SQL: Statement ignored
4/11 PLS-00201: identifier 'INVALID_ID' must be declared
6/10 PLS-00201: identifier 'INVALID_ID' must be declared
You need to declare the exceptions you use:
SQL> CREATE OR REPLACE PROCEDURE testException
2 IS
3 INVALID_ID exception;
4 BEGIN
5 raise INVALID_ID;
6 EXCEPTION
7 WHEN INVALID_ID THEN
8 dbms_output.put_line('Invalid ID');
9 END;
10 /
Procedure created.
In this DEMO you will see all 3 situation that this PROCEDURE should handle:
Here is the correct procedure:
CREATE OR REPLACE PROCEDURE raise_salary
(eid IN employees.e_id%TYPE,
raise IN employees.salary%type)
IS
cnt INTEGER;
sal employees.salary%TYPE;
INVALID_ID exception;
NULL_VALUE exception;
BEGIN
SELECT count(*)
INTO cnt
FROM employees
WHERE e_id=eid;
IF cnt=0 THEN
RAISE INVALID_ID;
ELSE
SELECT salary
INTO sal
FROM employees
WHERE e_id=eid;
IF sal IS NULL THEN
RAISE NULL_VALUE;
ELSE
UPDATE employees
SET salary = (SAL + raise)
WHERE e_id = eid;
dbms_output.put_line('Salary raised!');
END IF;
END IF;
exception
WHEN INVALID_ID THEN
dbms_output.put_line('User ID does not exist!');
WHEN NULL_VALUE THEN
dbms_output.put_line('Salary is null in table!');
WHEN others THEN
dbms_output.put_line('Error!');
END;
/
You had more than one errors and one was nicely explained by #Aleksej in his answer VOTE UP.
You also have a line:
SELECT salary INTO sal FROM employees WHERE e_id=eid;
But you have not declared sal.
Hope this helps...

Error at "dbms_output.put_line"?

I am creating a trigger in Oracle and we are stuggling with the syntax.
I have run it through a code checker several times but it keep saying we have an error at "dbms_output.put_line".
When we try to run it, the code says "trigger created with compilation errors"
CREATE TRIGGER date_trigger
BEFORE INSERT ON PrintJob
FOR EACH ROW
BEGIN
IF StartDate > SysDate THEN
BEGIN
dbms_output.put_line ('Please check date');
END;
Trigger can't reference table columns just by naming them - you'll need :old (or :new) pseudorecord qualifiers, such as in this modified example. It is not that DBMS_OUTPUT.PUT_LINE won't work; you wrote it correctly, but should replace it with the RAISE_APPLICATION_ERROR.
SQL> CREATE TABLE printjob (startdate DATE);
Table created.
SQL> CREATE OR REPLACE TRIGGER date_trigger
2 BEFORE INSERT
3 ON PrintJob
4 FOR EACH ROW
5 BEGIN
6 IF :new.StartDate > SYSDATE
7 THEN
8 -- dbms_output.put_line ('Please check date');
9 RAISE_APPLICATION_ERROR (-20000, 'Please check date');
10 END IF;
11 END;
12 /
Trigger created.
SQL> INSERT INTO printjob
2 VALUES (DATE '2018-02-20');
INSERT INTO printjob
*
ERROR at line 1:
ORA-20000: Please check date
ORA-06512: at "SCOTT.DATE_TRIGGER", line 5
ORA-04088: error during execution of trigger 'SCOTT.DATE_TRIGGER'
SQL>

How to skip unique constraint error

I am trying to insert values into sql table, but I am getting this error in sql query
SQL Error: ORA-00001: unique constraint (uniqueKey) violated
00001. 00000 - "unique constraint (%s.%s) violated"
*Cause: An UPDATE or INSERT statement attempted to insert a duplicate key.
For Trusted Oracle configured in DBMS MAC mode, you may see
this message if a duplicate entry exists at a different level.
*Action: Either remove the unique restriction or do not insert the key.
Is there a way to skip this error and continue insert. Something like this
try
insert query
catch (unique constraint error)
continue inserting other values
There exists hint ignore_row_on_dupkey_index(<table name>, <unique index name>).
HUSQVIK#hq_pdb_tcp> CREATE TABLE tmp (val NUMBER CONSTRAINT pk_tmp PRIMARY KEY);
Table created.
HUSQVIK#hq_pdb_tcp> INSERT /*+ ignore_row_on_dupkey_index(tmp, pk_tmp) */ INTO tmp (val) SELECT 1 FROM DUAL CONNECT BY LEVEL <= 3;
1 row created.
See that I insert three values of 1 and only one row was created.
There is a LOG ERRORS clause which allows you to log the rows that cause errors in to an error table - this error table is created using a DBMS package:
DBMS_ERRLOG.CREATE_ERROR_LOG(table_being_inserted_into ,name_of_table_for_errors ,NULL,NULL,TRUE);
https://docs.oracle.com/cd/B28359_01/appdev.111/b28419/d_errlog.htm
Function Signature:
DBMS_ERRLOG.CREATE_ERROR_LOG (
dml_table_name IN VARCHAR2,
err_log_table_name IN VARCHAR2 := NULL,
err_log_table_owner IN VARCHAR2 := NULL,
err_log_table_space IN VARCHAR2 := NULL,
skip_unsupported IN BOOLEAN := FALSE);
Then in your insert statement you end it with a log errors clause:
LOG ERRORS INTO your_error_table_name ( 'description of your choosing' ) REJECT LIMIT UNLIMITED;
You can choose to accept a reject limit of a fixed number, allowing you to specify in effect a tolerance to errors before it throws a real error instead of just allowing the row to be place in an error table.
simple sample is insert in for loop and ignore exceptions:
begin
for rc in (select * from <your query> loop
begin
insert into t1(...) values (...);
exceptions when others then
null;--ignore any exceptions do nothing
end;
end loop;
end
other sample - same idea but use FORALL bulk operation and SAVE EXCEPTIONS
declare
cursor C is
select ID, OWNER, OBJECT_NAME, SUBOBJECT_NAME, OBJECT_ID, DATA_OBJECT_ID,
decode( mod(rownum,100000), 1, rpad('*',20,'*'), OBJECT_TYPE ) object_type,
CREATED, LAST_DDL_TIME, TIMESTAMP, STATUS, TEMPORARY, GENERATED, SECONDARY
from big_table;
type array is table of c%rowtype;
l_data array;
dml_errors EXCEPTION;
PRAGMA exception_init(dml_errors, -24381);
l_errors number;
l_errno number;
l_msg varchar2(4000);
l_idx number;
begin
open c;
loop
fetch c bulk collect into l_data limit 100;
begin
forall i in 1 .. l_data.count SAVE EXCEPTIONS
insert into t2 values l_data(i);
exception
when DML_ERRORS then
l_errors := sql%bulk_exceptions.count;
for i in 1 .. l_errors
loop
l_errno := sql%bulk_exceptions(i).error_code;
--do smth with the exceptions
end loop;
end;
exit when c%notfound;
end loop;
close c;
end;
more information see on AskTom and OraMagazine
https://asktom.oracle.com/pls/asktom/f?p=100:11:0%3A%3A%3A%3AP11_QUESTION_ID:1422998100346727312
http://www.oracle.com/technetwork/issue-archive/2012/12-sep/o52plsql-1709862.html

How do you rollback to the next iteration in a loop?

To explain my question easier I will just paste my whole code:
drop table tst;
create table tst
(t1 number(2));
set serveroutput on
DECLARE
TYPE vltp IS TABLE OF NUMBER(3);
vl vltp := vltp(2,12,33,344,55,66,7,555,4);
NUMBER_TO_BIG EXCEPTION;
PRAGMA EXCEPTION_INIT(NUMBER_TO_BIG, -01438);
BEGIN
FOR i IN vl.FIRST .. vl.LAST LOOP
INSERT INTO tst VALUES (vl(i));
SAVEPOINT ONE;
END LOOP;
EXCEPTION
WHEN NUMBER_TO_BIG THEN
ROLLBACK TO SAVEPOINT ONE;
END;
/
select * from tst;
Basically, when I am inserting 344 into the table I get an exception (NUMBER_TO_BIG) and I want it to roll back to the loop but skip that number.
The expected output:
tst
-----
2
12
33
55
66
7
4
Actual output:
no rows selected
It is rolling back all the changes, not just that one number.
Any ideas?
You should handle the exception inside the loop itself. It will continue with the loop, once the exception is handled.
SQL> DECLARE
TYPE vltp IS TABLE OF NUMBER(3);
vl vltp := vltp(2,12,33,344,55,66,7,555,4);
NUMBER_TO_BIG EXCEPTION;
PRAGMA EXCEPTION_INIT(NUMBER_TO_BIG, -01438);
BEGIN
FOR i IN vl.FIRST .. vl.LAST LOOP
BEGIN
INSERT INTO tst VALUES (vl(i));
EXCEPTION
WHEN NUMBER_TO_BIG THEN
NULL;
END;
END LOOP;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(SQLERRM);
END;
/
PL/SQL procedure successfully completed.
SQL> SELECT * FROM tst;
T1
----------
2
12
33
55
66
7
4
7 rows selected.
you should try this...
drop table tst;
--create table
create table tst
(t1 number(2));
--start of code
DECLARE
TYPE vltp IS TABLE OF NUMBER(3);
vl vltp := vltp(2, 12, 33, 344, 55, 66, 7, 555, 4);
NUMBER_TO_BIG EXCEPTION;
PRAGMA EXCEPTION_INIT(NUMBER_TO_BIG, -01438);
BEGIN
FOR i IN vl.FIRST .. vl.LAST LOOP
begin
INSERT INTO tst VALUES (vl(i));
exception
when NUMBER_TO_BIG then
--log exeption into log table here
dbms_output.put_line(sqlerrm);
end;
END LOOP;
commit;
exception
when others then
--log exeption into log table here
dbms_output.put_line(sqlerrm);
END;
Hello i have illustrtaed a small snippet to replicate your scenario. Let me know if this helps.
--Check for existing table with same name and dropping if already exists
DROP TABLE tst;
--Create Table
CREATE TABLE tst
(t1 NUMBER(2)
);
--Anonymous block to perform the task
SET serveroutput ON
DECLARE
TYPE vltp
IS
TABLE OF NUMBER
(
3
)
;
vl vltp := vltp(2,12,33,344,55,66,7,555,4);
NUMBER_TO_BIG EXCEPTION;
PRAGMA EXCEPTION_INIT(NUMBER_TO_BIG, -01438);
BEGIN
FOR i IN vl.FIRST .. vl.LAST
LOOP
BEGIN
INSERT INTO tst VALUES
(vl(i)
);
EXCEPTION
WHEN NUMBER_TO_BIG THEN
NULL;
dbms_output.put_line('skipping the value');
END;
END LOOP;
COMMIT;
END;