Raise parent key integrity constraint in procedure for each column - oracle

I have the following code in a package which inserts data into table.
I am able to get parent key not found exception. How can I specifically get constraint violated message for each column? E.g. if proj_id is violated then raise exception, if proj_code is violated, then raise another exception.
PROCEDURE add_project(
p_proj_id project.proj_id%TYPE,
p_proj_desc project.proj_desc%TYPE,
p_proj_code project.proj_code%TYPE,
p_proj_date project.proj_date%TYPE
)
IS
parent_not_found exception;
pragma exception_init(parent_not_found, -2291);
BEGIN
INSERT
INTO projects (proj_id,proj_desc,proj_code,proj_date) values
(p_proj_id,p_proj_desc,p_proj_code,p_proj_date);
exception
when parent_not_found then
raise_application_error(-20001,'Invalid');
END;

Take a look at EXCEPTION_INIT Pragma.
DECLARE
l_parentnotfound exception;
l_res integer;
PRAGMA EXCEPTION_INIT(l_parentnotfound, -2291);
BEGIN
-- check if the parent key exists
select 1 into l_res from codes where code = proj_code;
-- if not, raise exception
if l_res <> 1 then
raise l_parentnotfound;
end if;
INSERT INTO projects (proj_id,proj_desc,proj_code,proj_date) values (p_proj_id,p_proj_desc,p_proj_code,p_proj_date);
EXCEPTION WHEN l_parentnotfound THEN
-- handle the error
END;
Or you can use WHEN OTHERS and look for the SQLCODE.
EDIT:
Note that you are not forced to manually check that the parent key exists to raise the exception, you can stay with :
DECLARE
l_parentnotfound exception;
l_res integer;
PRAGMA EXCEPTION_INIT(l_parentnotfound, -2291);
BEGIN
INSERT INTO projects (proj_id,proj_desc,proj_code,proj_date) values (p_proj_id,p_proj_desc,p_proj_code,p_proj_date);
EXCEPTION WHEN l_parentnotfound THEN
-- handle the error
END;
But if you want to be able to get violated constraint name easily, it can be useful to raise exception manually for each column. Also you can try to get the constraint name using USER_CONSTRAINTS and USER_CONS_COLUMNS.
Another way to get the violated constraint name is to parse the SQLERRM error message.

try
create PROCEDURE add_project(p_proj_id project.proj_id%TYPE,
p_proj_desc project.proj_desc%TYPE,
p_proj_code project.proj_code%TYPE,
p_proj_date project.proj_date%TYPE) IS
BEGIN
INSERT INTO projects
(proj_id, proj_desc, proj_code, proj_date)
values
(p_proj_id, p_proj_desc, p_proj_code, p_proj_date);
--add this
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
END;

Related

How to create user defined exception in a procedure?

Using a procedure adds an employee record into the employee table, also validates the input values salary must be always greater than or equal to 500, raise a user-defined exception for any validation error.
You can create something like this. Add parameters for other columns as well
CREATE OR REPLACE PROCEDURE insert_emp (salary NUMBER)
AS
invalid_salary EXCEPTION;
BEGIN
IF salary < 500 THEN
RAISE invalid_salary;
ELSE
INSERT INTO employees(salary) VALUES (salary);
COMMIT;
END IF;
END;
You can also associate an Exception number with the exception
Exception number for user-defined exceptions must be in the range of -20000 to -20999
CREATE OR REPLACE PROCEDURE insert_emp (salary NUMBER)
AS
invalid_salary EXCEPTION;
PRAGMA EXCEPTION_INIT (invalid_salary, -20100);
BEGIN
IF salary < 500 THEN
RAISE invalid_salary;
ELSE
INSERT INTO employees(salary) VALUES (salary);
COMMIT;
END IF;
END;
This sounds like a homework problem so I'll let using a trigger go, except a possible gotta and th show a better way of handling it. You raise the user defined exception "invalid salary" however unless your code handles it Oracle will throw the error "ORA-06510 Unhandled user defined exception", indicating it does not know what with it. So what is a better way: Define the column and include a check constraint on it.
Create table employees (...
, salary number(8,2) not null
constraint salary_less_then_minimum check (salary >= 500)
, ...);

oracle exception not going to exception block

I need to update some code which uses dynamic sql and potentially could have duplicate column names in the columns of the insert statement.
So I wanted to handle this, ORA-00957: Duplicate Column name. This error does not get handled by the most generic "when others" in the exception block. If I make it test a unique constraint violation it does.
Following some test code:
create table animal (id number , animal_type number,
animal_name varchar2(20), constraint id primary key(id));
-----------------------------------------------------
begin
for i in 1.. 100 loop
insert into animal(id, animal_type, animal_name)
values(i,floor(dbms_random.value(1,30)),'animal'||i);
end loop;
end;
-----------------------------------------------------
DECLARE
-- e_duplicate_column exception;
-- pragma exception_init(e_duplicate_column,-957);
BEGIN
insert into animal(id, animal_name, animal_name)
values(1000003, 'animal 1000003', 'animal 1000003');
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line(SQLCODE);
dbms_output.put_line(SQLERRM);
END;
I was trying to get the codes here as the pragma wasn't working(i.e. arriving) either. But that's not happening if it doesn't even get to "when others".
Any insights are appreciated.
Cheers, Robbert
PS oracle 12C, tried on sqldeveloper and toad
Your test code does not use dynamic SQL, which is required to generate an ORA-00957 error. Without dynamic SQL, Oracle will throw the ORA-00957 when it compiles your block, which I think you are misinterpreting as Oracle actually running you block and skipping the exception handler.
Try this instead as a test (make sure you have DBMS output enabled in your client!):
DECLARE
-- e_duplicate_column exception;
-- pragma exception_init(e_duplicate_column,-957);
BEGIN
execute immediate q'[insert into animal(id, animal_name, animal_name) values(1000003, 'animal 1000003', 'animal 1000003')]';
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line(SQLCODE);
dbms_output.put_line(SQLERRM);
END;
-957
ORA-00957: duplicate column name

Trigger not working for stopping table insert

I am using the following code for stopping null value insert into table using trigger. But when I pass null value, the inserting is happening fine. Any idea what am I doing wrong here?
create table test
(col1 number,
col2 varchar2(40)
)
create or replace trigger test_trg
after insert on test
for each row
declare
excp exception;
pragma autonomous_transaction;
begin
if :new.col2 is null then
RAISE excp;
end if;
exception
when excp then
dbms_output.put_line('error');
rollback;
end;
(Please note, I do accept that using a not null or a check constraint on the col2 is a better solution. I just want to find out the reason behind the error in this seemingly correct code)
Don't rollback in trigger, just re-raise excpetion after logging it:
create or replace trigger test_trg
after insert on test
for each row
declare
excp exception;
pragma autonomous_transaction;
begin
if :new.col2 is null then
RAISE excp;
end if;
exception
when excp then
dbms_output.put_line('error');
raise; -- propagate error
end;
When you put "exception ... end;" block in code you say to PL/SQL that managing consequences of this error is on your responsibility. So, if you don't raise any error from a code which handles original error, for PL/SQL it means that all actions regarding this error already done in your code, all went OK and record must be inserted.
You can try it in this SQLFiddle.
you have to define the trigger as BEFORE INSERT to fire before the insert is executed, remove the pragma autonomouse_transaction and the rollback (they have no sense here, because you do not any DML), then reraise the exception in the exception handler

PLSQL: BEFORE INSERT TRIGGER (check value in column from other table before allowing insert)

I've made a simple DVD store database. The DVD table has a column "status" which can be either 'FOR_RENT','FOR_SALE','RENTED',or 'SOLD'. I want to write a trigger to block any insertions into my RENTALS table if the status column in the DVD table is not set to 'FOR_RENT'.
Much of the documents I've looked at generally don't show example using values from two different tables so I'm a bit flummaxed.
This is what I believe has been my best attempt so far:
CREATE OR REPLACE TRIGGER RENTAL_UNAVAILABLE
BEFORE INSERT ON RENTAL;
FOR EACH ROW
WHEN (DVD.STATUS != 'FOR_RENT')
DECLARE
dvd_rented EXCEPTION;
PRAGMA EXCEPTION_INIT( dvd_rented, -20001 );
BEGIN
RAISE dvd_rented;
EXCEPTION
WHEN dvd_rented THEN
RAISE_APPLICATION_ERROR(-20001,'DVD has been rented');
END;
/
I'm getting this error:
ORA-00911: invalid character
Try this - I have not complied the code, but should be good. In case you see any compilation issues let me know and post schema on sqlfiddle.com
CREATE OR REPLACE TRIGGER rental_unavailable
BEFORE INSERT
ON rental
FOR EACH ROW
DECLARE
dvd_rented EXCEPTION;
PRAGMA EXCEPTION_INIT (dvd_rented, -20001);
n_count NUMBER (1);
BEGIN
SELECT COUNT (*)
INTO n_count
FROM dvd
WHERE dvd_id = :NEW.dvd_id AND dvd.status = 'FOR_RENT' AND ROWNUM < 2;
IF n_count > 0
THEN
RAISE dvd_rented;
END IF;
EXCEPTION
WHEN dvd_rented
THEN
raise_application_error (-20001, 'DVD has been rented');
END;

Handle ORACLE Exceptions

I need to handle the ORA-01400 error (cannot insert NULL into ("SCHEMA"."TABLE_NAME"."COLUMN_NAME") ) using a exception handle.
ORACLE Predefine a few Exceptions like (ACCESS_INTO_NULL, ZERO_DIVIDE and so on), but apparently does not define an Exception for the ORA-01400 error, how do I handle this particular error code?
I need something like this (other suggestions are accepted).
....
...
INSERT INTO MY_TABLE (CODE, NAME) VALUES (aCode,aName);
COMMIT;
EXCEPTION
WHEN NULL_VALUES THEN /* i don't know this value , exist?*/
Do_MyStuff();
WHEN OTHERS THEN
raise_application_error(SQLCODE,MY_OWN_FORMAT_EXCEPTION(SQLCODE,SQLERRM),TRUE);
END;
The pre-defined PL/SQL exceptions are special to Oracle. You really can't mess with those. When you want to have a set of predefined exceptions of your own you can't declare them "globally" like the standard ones. Instead, create an exceptions package which has all of the exception declarations and use that in your application code.
Example:
CREATE OR REPLACE PACKAGE my_exceptions
AS
insert_null_into_notnull EXCEPTION;
PRAGMA EXCEPTION_INIT(insert_null_into_notnull, -1400);
update_null_to_notnull EXCEPTION;
PRAGMA EXCEPTION_INIT(update_null_to_notnull, -1407);
END my_exceptions;
/
Now use the exception defined in the package
CREATE OR REPLACE PROCEDURE use_an_exception AS
BEGIN
-- application specific code ...
NULL;
EXCEPTION
WHEN my_exceptions.insert_null_into_notnull THEN
-- application specific handling for ORA-01400: cannot insert NULL into (%s)
RAISE;
END;
/
Source: http://www.orafaq.com/wiki/Exception
you can define your own exceptions, like variables (they will have the same scope as other variables so you can define package exception, etc...):
SQL> DECLARE
2 NULL_VALUES EXCEPTION;
3 PRAGMA EXCEPTION_INIT(NULL_VALUES, -1400);
4 BEGIN
5 INSERT INTO t VALUES (NULL);
6 EXCEPTION
7 WHEN null_values THEN
8 dbms_output.put_line('null value not authorized');
9 END;
10 /
null value not authorized
PL/SQL procedure successfully completed
You can handle exception by its code like this:
....
...
INSERT INTO MY_TABLE (CODE, NAME) VALUES (aCode,aName);
COMMIT;
EXCEPTION
WHEN OTHERS THEN
IF SQLCODE = -1400 THEN
Do_MyStuff();
ELSE
raise_application_error(SQLCODE,MY_OWN_FORMAT_EXCEPTION(SQLCODE,SQLERRM),TRUE);
END IF;
END;
INSERT INTO MY_TABLE (CODE, NAME) VALUES (aCode,aName);
COMMIT;
EXCEPTION
WHEN NULL_VALUES /* i don't know this value , exist?*/
emesg := SQLERRM;
dbms_output.put_line(emesg);
WHEN OTHERS THEN
emesg := SQLERRM;
dbms_output.put_line(emesg);
END;
SQLERRM shows the sql error message
http://www.psoug.org/reference/exception_handling.html

Resources