I'm really new to Oracle, I want to know how to continue to run my procedure if my trigger not detecting any errors.
I just want to continue to run my procedure if those two exception within trigger is not being triggered but when i run it shows me this error
ERROR at line 1:
ORA-01403: no data found
ORA-01403: no data found
ORA-06512: at "TEST.TRG_BOOKING_VALIDATION", line 9
ORA-04088: error during execution of trigger 'TEST.TRG_BOOKING_VALIDATION'
ORA-06512: at "TEST.PRC_ADD_BOOKING", line 44
ORA-06512: at line 1
PROCEDURE
create sequence bookingidvalue minvalue 1 start with 3031;
CREATE OR REPLACE PROCEDURE PRC_ADD_BOOKING(CUST_ID IN NUMBER,PAYMENT_ID IN NUMBER,FRM_DEST IN VARCHAR2,TO_DEST IN VARCHAR2)AS
v_journeystatus VARCHAR2(15) := 'Pending';
v_bookeddate Booking.bookingdate%TYPE;
no_null_on_custID EXCEPTION;
no_null_on_payID EXCEPTION;
no_null_on_FROM_DEST EXCEPTION;
no_null_on_TO_DEST EXCEPTION;
duplicate_error EXCEPTION;
BEGIN
IF CUST_ID < 0
THEN
RAISE no_null_on_custID;
END IF;
IF PAYMENT_ID < 0
THEN
RAISE no_null_on_payID;
END IF;
IF FRM_DEST IS NULL
THEN
RAISE no_null_on_FROM_DEST;
END IF;
IF TO_DEST IS NULL
THEN
RAISE no_null_on_TO_DEST;
END IF;
IF FRM_DEST = TO_DEST
THEN
RAISE duplicate_error;
END IF;
INSERT INTO Booking values(bookingidvalue.nextval,sysdate,v_journeystatus,FRM_DEST,TO_DEST,CUST_ID,PAYMENT_ID);
DBMS_OUTPUT.PUT_LINE('Booking has been added');
EXCEPTION
WHEN no_null_on_custID then
DBMS_OUTPUT.PUT_LINE('Invalid Customer ID');
WHEN no_null_on_payID then
DBMS_OUTPUT.PUT_LINE('Invalid Payment ID');
WHEN no_null_on_FROM_DEST then
DBMS_OUTPUT.PUT_LINE('From Destination must be filled');
WHEN no_null_on_TO_DEST then
DBMS_OUTPUT.PUT_LINE('To Destination must be filled');
WHEN duplicate_error then
DBMS_OUTPUT.PUT_LINE('From destination cannot same with To destination');
END;
/
TRIGGER
CREATE OR REPLACE trigger trg_booking_validation
before insert on booking
for each row
declare
v_journeystatus booking.journeystatus%type;
v_customerid booking.customerid%type;
v_paymentid booking.paymentid%type;
BEGIN
select bo.journeystatus into v_journeystatus
from booking bo
where bo.customerid = :new.customerid;
if SQL%FOUND then
case
when inserting then
if(v_journeystatus = 'In Journey')then
RAISE_APPLICATION_ERROR(-20950,'YOU ARE CURRENTLY IN JOURNEY, PLEASE BOOK AGAIN WHEN YOU REACHED');
end if;
if(v_journeystatus = 'Pending')then
RAISE_APPLICATION_ERROR(-20950,'YOUR PREVIOUS BOOKING IS ALREADY ON PENDING! DRIVER WILL SOON PICK YOU UP, BE PATIENCE!');
end if;
if(v_journeystatus = NULL)then
DBMS_OUTPUT.PUT_LINE('N0 errors');//i want to continue to my procedure here
end if;
end case;
end if;
END;
/
Catch the NO_DATA_FOUND exception in the trigger:
CREATE OR REPLACE trigger trg_booking_validation
before insert on booking
for each row
declare
v_journeystatus booking.journeystatus%type;
BEGIN
select bo.journeystatus
into v_journeystatus
from booking bo
where bo.customerid = :new.customerid;
if v_journeystatus = 'In Journey' then
RAISE_APPLICATION_ERROR(
-20950,
'YOU ARE CURRENTLY IN JOURNEY, PLEASE BOOK AGAIN WHEN YOU REACHED'
);
elsif v_journeystatus = 'Pending' then
RAISE_APPLICATION_ERROR(
-20950,
'YOUR PREVIOUS BOOKING IS ALREADY ON PENDING! DRIVER WILL SOON PICK YOU UP, BE PATIENCE!'
);
end if;
EXCEPTION
WHEN NO_DATA_FOUND THEN
NULL;
END;
/
Note: you do not need to check if you are INSERTING as the trigger will only trigger during an INSERT.
However, I'm not sure that you should be using a SELECT statement and should not just be checking the :NEW.journeystatus bind variable if you are referring to the row you are INSERTing:
CREATE OR REPLACE trigger trg_booking_validation
before insert on booking
for each row
BEGIN
if :NEW.journeystatus = 'In Journey' then
RAISE_APPLICATION_ERROR(
-20950,
'YOU ARE CURRENTLY IN JOURNEY, PLEASE BOOK AGAIN WHEN YOU REACHED'
);
elsif :NEW.journeystatus = 'Pending' then
RAISE_APPLICATION_ERROR(
-20950,
'YOUR PREVIOUS BOOKING IS ALREADY ON PENDING! DRIVER WILL SOON PICK YOU UP, BE PATIENCE!'
);
end if;
END;
/
Related
I am writing a procedure to delete department from a table. It takes depatment id as argument and delete the department with given id. but it is not working correctly.When i didnot use EXCEPTION, it only give output when gien department id is present in table but if the id is not present in table it throw error. When i use exception, It did not check the if else condition.
Here is my procedure
CREATE OR REPLACE PROCEDURE del_job(j_id number) IS
jj_id bb_department.iddepartment%type;
BEGIN
SELECT IDDEPARTMENT
INTO jj_id
FROM BB_DEPARTMENT
WHERE IDDEPARTMENT=j_id;
EXCEPTION
WHEN NO_DATA_FOUND THEN
jj_id := NULL;
IF (jj_id=j_id) THEN
DELETE FROM BB_DEPARTMENT
WHERE IDDEPARTMENT=j_id;
dbms_output.put_line ('Job Deleted');
ELSIF(jj_id=0) THEN
dbms_output.put_line ('No Job Deleted');
END IF;
END;
/
Your indentation seems to imply that you want your if statement to be part of the normal flow rather than part of the exception block. But your actual code has the if statement in the exception handler. Since you're assigning a null to jj_id in the exception handler before running the if statement and null is never equal to nor unequal to any value, neither your if nor your elsif clause can ever be true so neither dbms_output call will be made.
Assuming your indentation shows your actual intent, my guess is that you want a nested PL/SQL block for the select statement and exception handler.
CREATE OR REPLACE PROCEDURE del_job(j_id number) IS
jj_id bb_department.iddepartment%type;
BEGIN
BEGIN
SELECT IDDEPARTMENT
INTO jj_id
FROM BB_DEPARTMENT
WHERE IDDEPARTMENT=j_id;
EXCEPTION
WHEN NO_DATA_FOUND THEN
jj_id := NULL;
END;
IF (jj_id=j_id) THEN
DELETE FROM BB_DEPARTMENT
WHERE IDDEPARTMENT=j_id;
dbms_output.put_line ('Job Deleted');
ELSIF(jj_id=0) THEN
dbms_output.put_line ('No Job Deleted');
END IF;
END;
/
You are making things overly difficult. DELETE sets sql%rowcount to the number of rows processed. So there is no need to select the department; just delete the appropriate id. If you want a confirmation message then test sql%rowcount. If the row was deleted it will contain 1 (or greater), if the id did not exist it will contain 0. Print the appropriate message.
create or replace procedure del_job(j_id number) is
begin
delete
from bb_department
where iddepartment=j_id;
if sql%rowcount > 0 then
dbms_output.put_line ('Job Deleted');
else
dbms_output.put_line ('No Job Deleted');
end if;
end del_job;
/
I'm trying to create a code in which i delete a student from my table by specifying his nr_matr, but if i don't have that nr_matr in my table then i want to trow an exception.
this is my code:
CREATE OR REPLACE PACKAGE manager_faculty IS
PROCEDURE delete_stud (nr_matr student.nr_matricol%type);
END manager_faculty;
/
CREATE OR REPLACE PACKAGE BODY manager_faculty IS
PROCEDURE delete_stud (nr_matr student.nr_matricol%type) IS
BEGIN
DELETE from student
WHERE nr_matricol=nr_matr;
EXCEPTION
WHEN no_data_found THEN
SELECT COUNT(*) INTO counter FROM student WHERE nr_matricol=nr_matr;
IF counter = 0 THEN
raise_application_error (-20001, 'There is no student with the number' || nr_matr);
END IF;
END delete_stud;
END manager_faculty;
/
set serveroutput on;
BEGIN
manager_faculty.delete_stud(125);
END;
/
When i'm trying to compile my code it says that the package body was created whit compilation errors. What am i doing wrong?
The error is PLS-00201: identifier 'COUNTER' must be declared and you can find this out by running SHOW ERRORS; after trying to compile your package body.
You can fix it like this:
CREATE OR REPLACE PACKAGE BODY manager_faculty IS
PROCEDURE delete_stud (nr_matr student.nr_matricol%type)
IS
counter INT;
BEGIN
DELETE FROM student
WHERE nr_matricol=nr_matr;
EXCEPTION
WHEN no_data_found THEN
SELECT COUNT(*)
INTO counter
FROM student
WHERE nr_matricol=nr_matr;
IF counter = 0 THEN
raise_application_error (
-20001,
'There is no student with the number' || nr_matr
);
END IF;
END delete_stud;
END manager_faculty;
/
SHOW ERRORS;
However, the code won't run as you expect as DELETE FROM will not throw an exception if it does not delete any rows. You will need to check SQL%ROWCOUNT:
CREATE OR REPLACE PACKAGE BODY manager_faculty IS
PROCEDURE delete_stud (nr_matr student.nr_matricol%type)
IS
BEGIN
DELETE from student
WHERE nr_matricol=nr_matr;
IF SQL%ROWCOUNT = 0 THEN
raise_application_error (
-20001,
'There is no student with the number' || nr_matr
);
END IF;
END delete_stud;
END manager_faculty;
/
Aside from using SQL%ROWCOUNT as answered by MTO, you can also use SQL%NOTFOUND.
%NOTFOUND yields TRUE if an INSERT, UPDATE, or DELETE statement affected no rows, or a SELECT INTO statement returned no rows. Otherwise, it yields FALSE.
CREATE OR REPLACE PACKAGE BODY manager_faculty IS
PROCEDURE delete_stud (nr_matr student.nr_matricol%type)
IS
BEGIN
DELETE from student
WHERE nr_matricol=nr_matr;
IF SQL%NOTFOUND THEN
raise_application_error (
-20001,
'There is no student with the number' || nr_matr
);
END IF;
END delete_stud;
END manager_faculty;
You can read here, if you want to know other attributes of SQL Cursor.
I am creating a trigger below, as long as I insert something already existed in the table, then print other wise do nothing.
create or replace trigger TR_insert
Before INSERT On A
For each row
DECLARE
l_act integer;
l_name varchar(30);
l_minute integer;
Begin
select count(1) into l_act
From A
Where Activity=:new.Activity;
if(l_act>0) then
DBMS_OUTPUT.PUT_LINE ('There is duplicate.');
else
DBMS_OUTPUT.PUT_LINE('');
end if;
end;
It is working fine when I insert something existed, but when I insert new item, then it gives out error "SQL Error: ORA-01403: no data found", why is that please?
You're getting the error because your select does not return any value for your new item. The below shud work.
begin
select count(1) into l_act
From A
Where Activity=:new.Activity;
if(l_act>0) then
DBMS_OUTPUT.PUT_LINE ('There is duplicate.');
end if;
exception
when NO_DATA_FOUND then
DBMS_OUTPUT.PUT_LINE('');
end;
I am creating a trigger for insert.If one of the value is the same as that in the old table. then I print a message. Here is my code.
Create or replace trigger TR_insert_act
After INSERT On ACTIVITIES
For each row
DECLARE
l_act varchar(30);
Begin
select Activity into l_act
From ACTIVITIES;
if(:new.Activity in l_act) then
DBMS_OUTPUT.PUT_LINE ('There is duplicate.');
end if;
end;
It is not compiled with the error on select of l_act, what to do please?
You need a BEFORE trigger, and a WHERE condition.
The DBMS_OUTPUT will not display the error though.
Create or replace trigger TR_insert_act
before INSERT On ACTIVITIES
For each row
l_act number;
Begin
select count(1) into l_act
From ACTIVITIES
WHERE ACTIVITY = :new.Activity
if(l_act > 0 ) then
RAISE_APPLICATION_ERROR (
num => -20000,
msg => 'There is Duplicate');
end if;
end;
So the problem i am having is that if i execute the following procedure and the cursor doesnt find the parameter being passed, it continues to execute the block (insert statement) but instead of throwing the NO_DATA_FOUND exception error it throws a parent/foreign key error.
CREATE OR REPLACE PACKAGE ASSIGNMENT3 IS
PROCEDURE END_CAMPAIGN(CTITLE IN CAMPAIGN.CAMPAIGNTITLE%TYPE);
END ASSIGNMENT3;
/
CREATE OR REPLACE PACKAGE BODY ASSIGNMENT3 AS
PROCEDURE END_CAMPAIGN(CTITLE IN CAMPAIGN.CAMPAIGNTITLE%TYPE) IS
CURSOR ADCOST_CUR IS
SELECT ACTUALCOST
FROM ADVERTISEMENT
WHERE ADVERTISEMENT.CAMPAIGNTITLE = CTITLE;
V_TOTALCOST NUMBER;
BEGIN
V_TOTALCOST := 0;
FOR INVOICE_REC IN ADCOST_CUR
LOOP
V_TOTALCOST := V_TOTALCOST + INVOICE_REC.ACTUALCOST;
END LOOP;
INSERT INTO INVOICE(INVOICENO, CAMPAIGNTITLE, DATEISSUED, DATEPAID, BALANCEOWING, STATUS)
VALUES (AUTOINCREMENTINVOICE.nextval, CTITLE, SYSDATE, NULL,V_TOTALCOST,NULL);
EXCEPTION WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('ERROR:The campaign title you entered returned no record(s), please enter a valid campaign title.');
COMMIT;
END END_CAMPAIGN;
END ASSIGNMENT3;
/
SET SERVEROUTPUT ON
EXECUTE ASSIGNMENT3.END_CAMPAIGN('Panasonic 3D TV');
While the parent foreign key error is correct, i dont want the block to execeute if the cursor doesnt return a row. Why is this happening?
Also, in terms of placing the COMMIT, where exactly do i tell it to COMMIT? Before the exception or after?
This is for a uni assignment.
When you loop over a cursor like that, if the cursor finds no matching rows, the loop simply doesn't execute at all. A NO_DATA_FOUND exception would only be raised if you had a SELECT ... INTO ... statement inside the BEGIN/END block that did not return any rows.
Where you have the COMMIT placed now, it is part of the EXCEPTION block -- but your indentation implies that you want it to execute whether the exception occurred or not. In this case, I would just put the COMMIT immediately after the INSERT, since it only matters if the INSERT is successful.
"So is there no way to have the NODATAFOUND exception trigger when
using a cursor, if the CTITLE parameter isnt found in the table"
What you could do is test the value of V_TOTAL_COST. If it is zero raise an exception, like this:
PROCEDURE END_CAMPAIGN(CTITLE IN CAMPAIGN.CAMPAIGNTITLE%TYPE) IS
CURSOR ADCOST_CUR IS
SELECT ACTUALCOST
FROM ADVERTISEMENT
WHERE ADVERTISEMENT.CAMPAIGNTITLE = CTITLE;
V_TOTALCOST NUMBER;
BEGIN
V_TOTALCOST := 0;
FOR INVOICE_REC IN ADCOST_CUR
LOOP
V_TOTALCOST := V_TOTALCOST + INVOICE_REC.ACTUALCOST;
END LOOP;
if v_total_cost = 0 then
raise no_data_found;
end if;
INSERT INTO INVOICE(INVOICENO, CAMPAIGNTITLE, DATEISSUED, DATEPAID, BALANCEOWING, STATUS)
VALUES (AUTOINCREMENTINVOICE.nextval, CTITLE, SYSDATE, NULL,V_TOTALCOST,NULL);
COMMIT;
EXCEPTION WHEN NO_DATA_FOUND THEN
DBMS_OUTPUT.PUT_LINE('ERROR:The campaign title you entered returned no record(s), please enter a valid campaign title.');
END END_CAMPAIGN;
This assumes you have a business rule that ACTUAL_COST cannot be zero.
Alternatively, there is the clunkier workaround of incrementing a counter in the loop and testing whether it is zero after the loop.
As for where to place the commit I would say the answer is not inside the procedure. The client (sqlplus in this case) should determine if the transaction will commit or rollback as the call to end the campaign may be just a part of a wider process. Also assuming that a campaign can exist without any advertisements then I would have an explicit check that the campaign title is valid perhaps against the table of CAMPAIGN? as suggested below:
CREATE OR REPLACE PACKAGE ASSIGNMENT3 IS
PROCEDURE END_CAMPAIGN(CTITLE IN CAMPAIGN.CAMPAIGNTITLE%TYPE);
END ASSIGNMENT3;
/
CREATE OR REPLACE PACKAGE BODY ASSIGNMENT3 AS
PROCEDURE END_CAMPAIGN(CTITLE IN CAMPAIGN.CAMPAIGNTITLE%TYPE) IS
V_VALID_CAMPAIGN INTEGER;
V_TOTALCOST NUMBER;
BEGIN
-- Check this campaign title is valid
/* Will get you NO_DATA_FOUND here if CTITLE is invalid so wrap in
another BEGIN END block to throw own custom error that the client
of this procedure can handle (if it wants) */
BEGIN
SELECT 1
INTO V_VALID_CAMPAIGN
FROM CAMPAIGN
WHERE CAMPAIGNTITLE = CTITLE;
EXCEPTION
WHEN NO_DATA_FOUND THEN
RAISE_APPLICATION_ERROR(-20000,'The campaign title you entered returned no record(s), please enter a valid campaign title.');
END;
-- Now tot up the cost of ads in this campaign and raise the invoice
SELECT SUM(ACTUALCOST)
INTO V_TOTALCOST
FROM ADVERTISEMENT
WHERE ADVERTISEMENT.CAMPAIGNTITLE = CTITLE;
INSERT INTO INVOICE(INVOICENO, CAMPAIGNTITLE, DATEISSUED, DATEPAID, BALANCEOWING, STATUS)
VALUES (AUTOINCREMENTINVOICE.nextval, CTITLE, SYSDATE, NULL,V_TOTALCOST,NULL);
END END_CAMPAIGN;
END ASSIGNMENT3;
/
EXECUTE ASSIGNMENT3.END_CAMPAIGN('Panasonic 3D TV');
COMMIT;