How to create user defined exception in a procedure? - oracle

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)
, ...);

Related

PL/SQL Insert check

Just having a problem with ensuring a constraint is not violated.
Goal: To insert a record that does not violate a constraint.
Constraint: An order should not be allowed if it is discontinued or out of stock.
Now I have a procedure that I was working on and have the necessary syntax working. Just need the finishing touches to get this insert procedure working.
/* Creating Procedure */
CREATE PROCEDURE INSERT_ORDER_DETAIL(
--PARAMETERS
p_product_name IN VARCHAR,
p_unit_price IN NUMBER,
p_quantity IN NUMBER,
p_discount IN NUMBER) IS
--VARIABLES AND DECLARATION FOR PROCEDURE
p_order_id NUMBER;
PRODUCT_LIST PRODUCT%ROWTYPE;
Fail EXCEPTION;
BEGIN
-- Check for product availability
BEGIN
SELECT *
INTO PRODUCT_LIST
FROM PRODUCT
WHERE DISCONTINUED = 'N'; -- select all orders available
EXCEPTION
WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('ERROR ! PRODUCT IS UNAVAILABLE');
RAISE Fail;
END;
--generate new order ID
SELECT MAX(ORDER_ID)+1
INTO p_order_id
FROM ORDER_DETAIL;
-- INSERTING A NEW ORDER
INSERT INTO ORDER_DETAIL VALUES (p_order_id, p_product_name, p_unit_price, p_quantity, p_discount);
COMMIT;
DBMS_OUTPUT.PUT_LINE('DONE!');
EXCEPTION
WHEN Fail THEN
ROLLBACK;
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(SQLERRM);
ROLLBACK;
END INSERT_ORDER_DETAIL;
/
You have two simple approaches, implement either of them.
In your insert procedure, add an IF condition to check whether the product is available in the inventory against the input order, and put the INSERT statement inside the IF block. Else, raise an EXCEPTION product not available. Similarly check for quantity as well.
Or,
Create a FUNCTION based on above logic that returns TRUE if product exists. You could simply go for the count in the table for that matching product in the function.
Based on the function's return value TRUE, call the INSERT procedure. Else, if FALSE, raise an exception that product is not available.
Put all the functions, procedures in one package.

How to put 2 condition after AS in a procedure

I want to put 2 condition after the keyword AS in a procedure which are INVALID_BUDGET EXCEPTION and Event_ID varchar2(8) but this will cause error in oracle.
CREATE OR REPLACE PROCEDURE PRC_ADD_OVER_BUDGET_EVENT(V_EventType IN VARCHAR,V_EventBudget IN NUMBER,V_organizerID IN VARCHAR,v_FoodBeverage IN NUMBER,v_wine IN NUMBER ,v_Decoration IN NUMBER,v_rentalfee IN NUMBER,v_facility IN NUMBER)
AS INVALID_BUDGET EXCEPTION AND Event_ID varchar2(8);
PRAGMA exception_init(INVALID_BUDGET,-20000);
BEGIN
INSERT INTO Event values ( next_eventid_seq,v_eventType,v_eventbudget,null,null,null,v_organizerID) RETURNING EVENTid INTO event_ID;
INSERT INTO EventCost values (next_Costid_seq,v_FoodBeverage,v_Wine,v_Decoration,v_RentalFee,v_Facility,event_ID);
EXCEPTION WHEN INVALID_BUDGET THEN DBMS_OUTPUT.PUT_LINE(u'\000A' || 'Please enter budget of above 50000.');
End;
/
How to put the two condition in a procedure without any error.
Extra question: Can procedure handle two exception handler?
For multiple exception handling in oracle you can use this syntax. The exception-handling block contains series of WHEN condition to handle the exception.
BEGIN
<execution block>
.
.
EXCEPTION
WHEN <exceptionl_name>
THEN
<Exception handling code for the “exception 1 _name’' >
WHEN OTHERS
THEN
<Default exception handling code for all exceptions >
END;
Please refer the link
Variable definitions are separated by a semi-colon:
CREATE OR REPLACE PROCEDURE PRC_ADD_OVER_BUDGET_EVENT
(V_EventType IN VARCHAR,
V_EventBudget IN NUMBER,
V_organizerID IN VARCHAR,
v_FoodBeverage IN NUMBER,
v_wine IN NUMBER,
v_Decoration IN NUMBER,
v_rentalfee IN NUMBER,
v_facility IN NUMBER)
AS
INVALID_BUDGET EXCEPTION;
Event_ID varchar2(8);
PRAGMA exception_init(INVALID_BUDGET,-20000);
BEGIN
INSERT INTO Event
values (next_eventid_seq, v_eventType, v_eventbudget,
null, null, null, v_organizerID)
RETURNING EVENTid INTO event_ID;
INSERT INTO EventCost
values (next_Costid_seq, v_FoodBeverage, v_Wine, v_Decoration,
v_RentalFee, v_Facility, event_ID);
EXCEPTION
WHEN INVALID_BUDGET THEN
DBMS_OUTPUT.PUT_LINE(u'\000A' || 'Please enter budget of above 50000.');
WHEN DUP_VAL_ON_INDEX THEN
DBMS_OUTPUT.PUT_LINE(u'\000A' || 'Attempt to insert duplicate value ' ||
SQLERRM);
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(u'\000A' || 'Something bad happened! ' || SQLERRM);
End;
And you can add as many exception handlers to your exception block as you want.
Best of luck.

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;

Resources