Stored Procedure two exception select statements - sql

I am having some trouble with my Stored Procedure in Oracle 12.1
The blow code is getting an error and I think it has to do with using two EXCEPTION statements in a row?
I am created a stored Procedure for a fake small online DVD company that updates the queue position in the rental queue table. I use an IF statement that says if the member already has this DVD in the queue, then updates the queue position. In order to check if the member already has a DVD in the queue I write an SQL Select statement that checks for the DVD in the members queue. If the statement finds a DVD then it inserts it into "dvd_check". If no DVD is found then i place DVD_check to equal 0.
I also have a 2nd SQL statement to determine the original queue order of the row that is about to be updated. Both Statements run great on their own within the stored procedure but when I put them together in the StoredProcedure before my IF statement, then I get an error:
Error(17,5): PLS-00103: Encountered the symbol "EXCEPTION" when expecting one of the following: ( begin case declare end exit for goto if loop mod null...
AND
Error(29,4): PLS-00103: Encountered the symbol "end-of-file" when expecting one of the following: end not pragma final instantiable order overriding static...
Here is my Code:
CREATE OR REPLACE PROCEDURE sp_queueorder (
dvdid_sp number,
memberid_sp number,
queueposition_sp number)
IS
dvd_check number;
old_queueposition number;
BEGIN
SELECT dvdid INTO dvd_check FROM rentalqueue
WHERE DVDid = dvdid_sp and memberid = memberid_sp;
EXCEPTION
WHEN no_data_found THEN dvd_check := 0;
SELECT queueposition INTO old_queueposition FROM rentalqueue
WHERE DVDid = dvdid_sp and memberid = memberid_sp;
EXCEPTION
WHEN no_data_found THEN old_queueposition := 0;
IF dvd_check > 0 THEN
UPDATE rentalqueue SET queueposition = queueposition + 1
WHERE memberid = memberid_sp and queueposition >= queueposition_sp AND queueposition <= old_queueposition;
UPDATE rentalqueue SET queueposition = queueposition_sp
WHERE dvdid = dvdid_sp AND memberid = memberid_sp;
END IF;
END;
Thanks so much for helping me solve this issue.

CREATE OR REPLACE PROCEDURE sp_queueorder (
dvdid_sp number,
memberid_sp number,
queueposition_sp number)
IS
dvd_check number;
old_queueposition number;
BEGIN
-- 1st select
BEGIN
SELECT dvdid INTO dvd_check FROM rentalqueue
WHERE DVDid = dvdid_sp and memberid = memberid_sp;
EXCEPTION
WHEN no_data_found THEN dvd_check := 0;
END;
-- 2nd select
BEGIN
SELECT queueposition INTO old_queueposition FROM rentalqueue
WHERE DVDid = dvdid_sp and memberid = memberid_sp;
EXCEPTION
WHEN no_data_found THEN old_queueposition := 0;
END;
IF dvd_check > 0 THEN
UPDATE rentalqueue SET queueposition = queueposition + 1
WHERE memberid = memberid_sp and queueposition >= queueposition_sp AND queueposition <= old_queueposition;
UPDATE rentalqueue SET queueposition = queueposition_sp
WHERE dvdid = dvdid_sp AND memberid = memberid_sp;
COMMIT; -- if is not needed remove
END IF;
END;

There is a missing END; in your code. Depending on how control is supposed to flow it might be supposed to look like this:
CREATE OR REPLACE PROCEDURE sp_queueorder (
dvdid_sp number,
memberid_sp number,
queueposition_sp number)
IS
dvd_check number;
old_queueposition number;
BEGIN
SELECT dvdid INTO dvd_check FROM rentalqueue
WHERE DVDid = dvdid_sp and memberid = memberid_sp;
EXCEPTION
WHEN no_data_found THEN dvd_check := 0;
---add an END; to the block here?
END;
SELECT queueposition INTO old_queueposition FROM rentalqueue
WHERE DVDid = dvdid_sp and memberid = memberid_sp;
EXCEPTION
WHEN no_data_found THEN old_queueposition := 0;
----or add an end here?
END;
IF dvd_check > 0 THEN
UPDATE rentalqueue SET queueposition = queueposition + 1
WHERE memberid = memberid_sp and queueposition >= queueposition_sp AND queueposition <= old_queueposition;
UPDATE rentalqueue SET queueposition = queueposition_sp
WHERE dvdid = dvdid_sp AND memberid = memberid_sp;
END IF;
END;
--or add it here?
END;

You have exceptions in the middle of the code. You must structure your code to look like this:
begin
begin
select ...
exception
when no_data_found ..
end;
begin
select ...
exception
when no_data_found ..
end;
...
end;

Related

PLS-00103 Encountered the symbol "END"

I'm running into the issue PL-00103: Encountered the symbol "END" on the second to last line of the following procedure. The purpose of the procedure is to see if a previous version of an email exists when a new one is sent... and expire the old email. (emails are by default set to a far away expiration date when created so I check to see if the expiration date is further than the current date).
PROCEDURE EXPIRE_STUFF_PRC
(
PI_EMAIL_NBR_STR IN VARCHAR2,
PO_SUCCESS_FLG OUT VARCHAR2,
PO_OUT_MSG OUT VARCHAR2
) AS
L_SUCCESS VARCHAR2(1) := 'N';
L_EMAIL_ID NUMBER;
L_PREV_EMAIL_VER_ID NUMBER := 0;
L_PREV_EMAIL_EXP_DT DATE;
BEGIN
BEGIN
SELECT
ITEM.EMAIL_ID
INTO L_EMAIL_ID
FROM HR_EMAIL ITEM
WHERE ITEM.EMAIL_NBR_STR = PI_EMAIL_NBR_STR;
END;
BEGIN
SELECT
VER_ID.EMAIL_VER_ID
INTO L_PREV_EMAIL_VER_ID
FROM (
SELECT
EMAIL_VER_ID
FROM HR_EMAIL_VER
WHERE EMAIL_ID = L_EMAIL_ID
ORDER BY EMAIL_VER_ID DESC
) VER_ID
WHERE ROWNUM = 2;
EXCEPTION
WHEN NO_DATA_FOUND
THEN PO_SUCCESS_FLG := 'Y';
PO_OUT_MSG := 'LESS THAN 2 VERSIONS';
END;
END;
BEGIN
IF (L_PREV_EMAIL_VER_ID > 0) THEN
SELECT
VER.EXP_DT
INTO L_PREV_EMAIL_EXP_DT
FROM HR_EMAIL_VER VER
WHERE VER.EMAIL_VER_ID = L_PREV_EMAIL_VER_ID;
IF (L_PREV_EMAIL_EXP_DT > SYSDATE) THEN
UPDATE HR_EMAIL_VER
SET EXP_DT = SYSDATE
WHERE EMAIL_VER_ID = L_PREV_EMAIL_VER_ID;
END IF;
PO_SUCCESS_FLG := 'Y';
PO_OUT_MSG := 'SUCCESS';
END IF;
END;
END;
END EXPIRE_STUFF_PRC;
I've tried to move around ENDs and BEGINs to no avail...
I've changed the name of stuff due to NDA so if there is any confusion I'll be happy to clarify as I might have missed something.
Thank you in advance for any help!
You have used unnecessary BEGIN/END in your code. There could be a necessity if you want to handle exceptions in a particular section. The best way to format and check for syntax is to use a nice code editor.
I have removed all the unwanted BEGIN/END and this should compile fine:
CREATE OR REPLACE PROCEDURE expire_stuff_prc (
pi_email_nbr_str IN VARCHAR2,
po_success_flg OUT VARCHAR2,
po_out_msg OUT VARCHAR2
) AS
l_success VARCHAR2(1) := 'N';
l_email_id NUMBER;
l_prev_email_ver_id NUMBER := 0;
l_prev_email_exp_dt DATE;
BEGIN
SELECT
item.email_id
INTO l_email_id
FROM
hr_email item
WHERE
item.email_nbr_str = pi_email_nbr_str;
BEGIN
SELECT
ver_id.email_ver_id
INTO l_prev_email_ver_id
FROM
(
SELECT
email_ver_id
FROM
hr_email_ver
WHERE
email_id = l_email_id
ORDER BY
email_ver_id DESC
) ver_id
WHERE
ROWNUM = 2;
EXCEPTION
WHEN no_data_found THEN
po_success_flg := 'Y';
po_out_msg := 'LESS THAN 2 VERSIONS';
END;
IF ( l_prev_email_ver_id > 0 ) THEN
SELECT
ver.exp_dt
INTO l_prev_email_exp_dt
FROM
hr_email_ver ver
WHERE
ver.email_ver_id = l_prev_email_ver_id;
IF ( l_prev_email_exp_dt > sysdate ) THEN
UPDATE hr_email_ver
SET
exp_dt = sysdate
WHERE
email_ver_id = l_prev_email_ver_id;
END IF;
po_success_flg := 'Y';
po_out_msg := 'SUCCESS';
END IF;
END expire_stuff_prc;
/
Ideal way to write a stored procedure is to handle all exception for each of the block/statement. You have one additional END that has to be removed, additionally i have added messages to be returned when first and last block goes into any exception.
Block is in sense logically grouped DML operation, it can be just a single select or group of DML operation.Decision to be taken based on the business logic.
PROCEDURE EXPIRE_STUFF_PRC
(
PI_EMAIL_NBR_STR IN VARCHAR2,
PO_SUCCESS_FLG OUT VARCHAR2,
PO_OUT_MSG OUT VARCHAR2
) AS
L_SUCCESS VARCHAR2(1) := 'N';
L_EMAIL_ID NUMBER;
L_PREV_EMAIL_VER_ID NUMBER := 0;
L_PREV_EMAIL_EXP_DT DATE;
BEGIN
BEGIN
SELECT
ITEM.EMAIL_ID
INTO L_EMAIL_ID
FROM HR_EMAIL ITEM
WHERE ITEM.EMAIL_NBR_STR = PI_EMAIL_NBR_STR;
EXCEPTION WHEN OTHERS THEN
PO_SUCCESS_FLG := 'Y';
PO_OUT_MSG := 'COULD NOT FETCH EMAIL_ID';
END;
BEGIN
SELECT
VER_ID.EMAIL_VER_ID
INTO L_PREV_EMAIL_VER_ID
FROM (
SELECT
EMAIL_VER_ID
FROM HR_EMAIL_VER
WHERE EMAIL_ID = L_EMAIL_ID
ORDER BY EMAIL_VER_ID DESC
) VER_ID
WHERE ROWNUM = 2;
EXCEPTION
WHEN NO_DATA_FOUND
THEN PO_SUCCESS_FLG := 'Y';
PO_OUT_MSG := 'LESS THAN 2 VERSIONS';
END;
BEGIN
IF (L_PREV_EMAIL_VER_ID > 0) THEN
SELECT
VER.EXP_DT
INTO L_PREV_EMAIL_EXP_DT
FROM HR_EMAIL_VER VER
WHERE VER.EMAIL_VER_ID = L_PREV_EMAIL_VER_ID;
IF (L_PREV_EMAIL_EXP_DT > SYSDATE) THEN
UPDATE HR_EMAIL_VER
SET EXP_DT = SYSDATE
WHERE EMAIL_VER_ID = L_PREV_EMAIL_VER_ID;
END IF;
PO_SUCCESS_FLG := 'Y';
PO_OUT_MSG := 'SUCCESS';
END IF;
EXCEPTION
WHEN OTHERS THEN
PO_SUCCESS_FLG := 'Y';
PO_OUT_MSG := 'UNABLE TO UPDATE HR_EMAIL_VER';
END;
END EXPIRE_STUFF_PRC;

I want to create trigger but I dont know how to do that. Below is the sample

I want to create trigger but I don't know how to do that. Below is the sample:
CREATE OR REPLACE TRIGGER checkDuration
after UPDATE on comm_shipping
FOR EACH ROW
DECLARE
quantity NUMBER;
BEGIN
SELECT * FROM comm_orders c
WHERE C.ORDER_ID = :new.order_id
AND c.quantity = 1;
IF quantity=NULL THEN
RAISE_APPLICATION_ERROR('no more items');
END IF;
EXCEPTION
WHEN NO_DATA_FOUND THEN
NULL;
END;
Try the following ( I suppose your DBMS is Oracle or DB2 because of RAISE_APPLICATION_ERROR ):
CREATE OR REPLACE TRIGGER checkDuration
AFTER UPDATE ON comm_shipping
FOR EACH ROW
DECLARE
quantity NUMBER;
BEGIN
SELECT c.quantity
INTO quantity -- this part is missing
FROM comm_orders c
WHERE c.order_id = :new.order_id;
IF quantity is NULL THEN
RAISE_APPLICATION_ERROR(-20001,'no more items'); -- you need a code
-- between -20000 and -20999
END IF;
EXCEPTION WHEN NO_DATA_FOUND THEN NULL;
END;

Encountered the symbol "EXCEPTION" error in stored procedure

I am programming a procedure in an Oracle Database 12c Enterprise Edition Release 12.1.0.2.0 - 64bit Production.
I have an exception inside a LOOP because I don't want the procedure to exit the LOOP if an exception is thrown.
create or replace procedure PARSE_REGISTER_MESSAGE
IS
HOTELS_TO_PROCESS number := 5000;
cursor unparsed_messages is
SELECT REGISTER_psd_id, message
FROM
( SELECT REGISTER_psd_id, message
FROM cc_owner.REGISTER_psd
WHERE parsed != 1
OR parsed IS NULL
ORDER BY CREATION_DATE DESC)
WHERE rownum < HOTELS_TO_PROCESS;
BEGIN
FOR psd_rec in unparsed_messages
LOOP
p_msg.parse_msg (psd_rec.REGISTER_psd_id, null, psd_rec.message);
EXCEPTION
WHEN OTHERS
THEN
DECLARE
l_code INTEGER := SQLCODE;
BEGIN
of_owner.p_db_trc.add_error
( 'PARSE_REGISTER_MESSAGE','',
l_code,
sys.DBMS_UTILITY.format_error_stack,
sys.DBMS_UTILITY.format_error_backtrace,
sys.DBMS_UTILITY.format_call_stack );
END;
END LOOP;
END;
But I can't compile the package due this error:
Error(25,10): PLS-00103: Encountered the symbol "EXCEPTION" when expecting one of the following:
( begin case declare end exit for goto if loop mod null pragma raise return select update while with << continue close current delete fetch lock insert open rollback savepoint set sql execute commit forall merge pipe purge
I Also tried:
create or replace procedure PARSE_REGISTER_MESSAGE
IS
HOTELS_TO_PROCESS number := 5000;
cursor unparsed_messages is
SELECT REGISTER_psd_id, message
FROM
( SELECT REGISTER_psd_id, message
FROM cc_owner.REGISTER_psd
WHERE parsed != 1
OR parsed IS NULL
ORDER BY CREATION_DATE DESC)
WHERE rownum < HOTELS_TO_PROCESS;
psd_rec unparsed_messages%ROWTYPE;
BEGIN
FOR psd_rec in unparsed_messages
LOOP
BEGIN
p_msg.parse_msg (psd_rec.REGISTER_psd_id, null, psd_rec.message);
EXCEPTION
WHEN OTHERS
THEN
DECLARE
l_code INTEGER := SQLCODE;
BEGIN
of_owner.p_db_trc.add_error
( 'PARSE_REGISTER_MESSAGE','',
l_code,
sys.DBMS_UTILITY.format_error_stack,
sys.DBMS_UTILITY.format_error_backtrace,
sys.DBMS_UTILITY.format_call_stack );
END;
END LOOP;
END;
But then I got this error:
Error(48,4): PLS-00103: Encountered the symbol ";" when expecting one of the following: loop
Try using Begin after loop keyword as one BEGIN is missing
FOR psd_rec in unparsed_messages
LOOP
BEGIN
p_msg.parse_msg (psd_rec.REGISTER_psd_id, null, psd_rec.message);
EXCEPTION
WHEN OTHERS
THEN
DECLARE
l_code INTEGER := SQLCODE;
BEGIN
of_owner.p_db_trc.add_error
( 'PARSE_REGISTER_MESSAGE','',
l_code,
sys.DBMS_UTILITY.format_error_stack,
sys.DBMS_UTILITY.format_error_backtrace,
sys.DBMS_UTILITY.format_call_stack );
END;
The syntax for a PLSQL block / procedure is :
DECLARE
-- Here you declare all the varaible used in block
BEGIN
-- Here you write the body of the Block
EXCEPTION
-- Here you write the exceptions which you want to handle.
END;
Now when i look at your code, you have written Exception block inside the FOR LOOP, which will work only if you use the above syntax. In you case the scope of Exception block is not identified by Oracle and hence it throws error.
FOR psd_rec IN unparsed_messages
LOOP
p_msg.parse_msg (psd_rec.REGISTER_psd_id, NULL, psd_rec.MESSAGE);
EXCEPTION --<-- Wrong way of using Excepton block. Scope of this Exception block is not resolved
WHEN OTHERS
THEN
DECLARE
l_code INTEGER := SQLCODE;
BEGIN
of_owner.p_db_trc.add_error
( 'PARSE_REGISTER_MESSAGE','',
l_code,
sys.DBMS_UTILITY.format_error_stack,
sys.DBMS_UTILITY.format_error_backtrace,
sys.DBMS_UTILITY.format_call_stack );
END;
You must modify your code as below to include the Exception block in for loop;
CREATE OR REPLACE PROCEDURE PARSE_REGISTER_MESSAGE
IS
HOTELS_TO_PROCESS NUMBER := 5000;
l_code INTEGER := SQLCODE;
CURSOR unparsed_messages
IS
SELECT REGISTER_psd_id, MESSAGE
FROM ( SELECT REGISTER_psd_id, MESSAGE
FROM cc_owner.REGISTER_psd
WHERE parsed != 1 OR parsed IS NULL
ORDER BY CREATION_DATE DESC)
WHERE ROWNUM < HOTELS_TO_PROCESS;
BEGIN
FOR psd_rec IN unparsed_messages
LOOP
BEGIN
p_msg.parse_msg (psd_rec.REGISTER_psd_id, NULL, psd_rec.MESSAGE);
EXCEPTION
WHEN OTHERS
THEN
of_owner.p_db_trc.add_error (
'PARSE_REGISTER_MESSAGE',
'',
l_code,
sys.DBMS_UTILITY.format_error_stack,
sys.DBMS_UTILITY.format_error_backtrace,
sys.DBMS_UTILITY.format_call_stack);
END;
END LOOP;
EXCEPTION
WHEN OTHERS
THEN
DBMS_OUTPUT.put_line (SQLERRM);
END;
You second try has missing END statement and thats why you were getting error. See below:
CREATE OR REPLACE PROCEDURE PARSE_REGISTER_MESSAGE
IS
HOTELS_TO_PROCESS NUMBER := 5000;
l_code INTEGER := SQLCODE;
CURSOR unparsed_messages
IS
SELECT REGISTER_psd_id, MESSAGE
FROM ( SELECT REGISTER_psd_id, MESSAGE
FROM cc_owner.REGISTER_psd
WHERE parsed != 1 OR parsed IS NULL
ORDER BY CREATION_DATE DESC)
WHERE ROWNUM < HOTELS_TO_PROCESS;
psd_rec unparsed_messages%ROWTYPE;
BEGIN
FOR psd_rec IN unparsed_messages
LOOP
BEGIN
p_msg.parse_msg (psd_rec.REGISTER_psd_id, NULL, psd_rec.MESSAGE);
EXCEPTION
WHEN OTHERS
THEN
BEGIN
of_owner.p_db_trc.add_error (
'PARSE_REGISTER_MESSAGE',
'',
l_code,
sys.DBMS_UTILITY.format_error_stack,
sys.DBMS_UTILITY.format_error_backtrace,
sys.DBMS_UTILITY.format_call_stack);
END;
END;
END LOOP;
END;

Trigger compilation error

I need some help in creating a trigger.
create or replace trigger trigger_one
before insert on Funtom_timesheet
for each row
Declare
V_id number;
V_hours number;
Begin
Select max(timesheet_ID)+1 into v_id from Funtom_timesheet
:new.timesheet_ID :=v_id;
select grade_hours into V_hours
from funtom_grade join funtom_employee
on emp_grade = grade_id
where empid = :new.timesheet_emp;
if V_hours >:new.timesheet_hours
else
:new.timesheet_overtime :=
:new.timesheet_hours-V_hours
:new.timesheet_hours:= V_hours;
END IF;
END;
/
please tell me which part of my code is wrong so I could work on it,
Thanks
You have many syntax errors - missing ; and then. There can't be if only with else part and without expression on it.
CREATE OR REPLACE TRIGGER TRIGGER_ONE
BEFORE INSERT ON FUNTOM_TIMESHEET
FOR EACH ROW
DECLARE
V_ID NUMBER;
V_HOURS NUMBER;
BEGIN
SELECT MAX(TIMESHEET_ID) + 1 INTO V_ID FROM FUNTOM_TIMESHEET;
:NEW.TIMESHEET_ID := V_ID;
SELECT GRADE_HOURS
INTO V_HOURS
FROM FUNTOM_GRADE
JOIN FUNTOM_EMPLOYEE
ON EMP_GRADE = GRADE_ID
WHERE EMPID = :NEW.TIMESHEET_EMP;
IF V_HOURS > :NEW.TIMESHEET_HOURS THEN
NULL;
ELSE
:NEW.TIMESHEET_OVERTIME := :NEW.TIMESHEET_HOURS - V_HOURS;
:NEW.TIMESHEET_HOURS := V_HOURS;
END IF;
END;
/
Also better use SEQUENCES instead of:
SELECT MAX(TIMESHEET_ID) + 1 INTO V_ID FROM FUNTOM_TIMESHEET;
:NEW.TIMESHEET_ID := V_ID;
When selecting form the same table as inserting, you can get MUTATING trigger error (http://www.dba-oracle.com/t_avoiding_mutating_table_error.htm)

Bind variable error in SQL trigger

Here is my trigger.Following error.
45 /
SP2-0552: Bind variable "OLD" not declared.
I am unable to find the error .I have tried several times but failed.I have declared every variable but the error is showing.Someone please help me .
drop trigger DELETE_Single_food
CREATE OR REPLACE TRIGGER DELETE_Single_food
BEFORE DELETE ON SingleFoodOrder
FOR EACH ROW
declare
f_price number;
old_bill number;
f_quantity number;
p_bill number;
foodID number;
orderID number;
order_date Date;
s_date Date;
f_date Date;
f_dis number;
a number;
b number;
c number;
BEGIN
IF :old.H_delivery_ID is not NULL then
foodID := :old.Fooditem_ID;
orderID := :old.H_delivery_ID;
f_quantity := :old.Quantity;
select bill into old_bill from HomeDelivery where H_delivery_ID =orderID ;
select price into f_price from Food_Item where Fooditem_ID = foodID;
select discount_percentage into f_dis from Food_Item where Fooditem_ID = foodID;
select start_date into s_date from Food_Item where Fooditem_ID = foodID;
select deadline into f_date from Food_Item where Fooditem_ID = foodID;
select H_delivery_request into order_date from HomeDelivery where H_delivery_ID =orderID;
if f_dis is not NULL then
if (order_date >= s_date and order_date<=f_date) then
a := f_dis/100;
b := f_price*a ;
c := f_price-b;
p_bill := old_bill-( c*f_quantity);
update HomeDelivery set bill = p_bill where H_delivery_ID = orderID;
else
p_bill := old_bill-(f_price*f_quantity);
update HomeDelivery set bill = p_bill where H_delivery_ID = orderID;
end if;
else
p_bill := old_bill-(f_price*f_quantity);
update HomeDelivery set bill = p_bill where H_delivery_ID = orderID;
end if;
END;
/
The problem is not in your variables declarations. I think you're not closing your main IF statement:
IF :old.H_delivery_ID is not NULL then
I don't see the END IF for that one. Add END IF; before the END;
If this does not work, you will need to do some debugging. Try just to leave only that statement in the begin block.
CREATE OR REPLACE TRIGGER DELETE_Single_food
BEFORE DELETE ON SingleFoodOrder
FOR EACH ROW
BEGIN
IF :old.H_delivery_ID is not NULL then
null;
END IF;
END;
/
See if that compiles. Then add the rest of the code to see where it breaks.
Hope this helps!