Encountered the symbol "EXCEPTION" error in stored procedure - sql

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;

Related

How do I fix the error : Encountered the symbol "EXCEPTION" when expecting one of the following: ( begin case declare end exit for goto

I get this erro when I try to raise an exception when no data is found.
Error at line 99/42: ORA-06550: line 89, column 8:
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
json_exists json_value json_query json_object json_array
BEGIN
DECLARE
p_amt number;
p_user_id number;
p_reference varchar2(100);
p_name varchar2(100);
p_narration varchar2(100);
p_payment_date DATE default sysdate;
p_net_amt NUMBER default null;
p_payment_type_id number;
p_transaction_type_id number;
p_payment_id number;
p_payment_email varchar2(500);
BEGIN
for c in (
SELECT
amount,
reference,
type,
narration,
paid_at,
net_amt,
payment_type_id,
transaction_type_id,
payment_id,
payment_email
INTO
p_amt,
p_reference,
p_name,
p_narration,
p_payment_date,
p_net_amt,
p_payment_type_id,
p_transaction_type_id,
p_payment_id,
p_payment_email
FROM pstk_payload p, JSON_TABLE(
p.webhook_payload,'$'
COLUMNS (
amount varchar2(500) path '$.data.amount',
reference varchar2(500) path '$.data.reference',
type varchar2(500) path '$.data.fees_breakdown.type',
narration varchar2(500) path '$.data.authorization.narration',
paid_at DATE path '$.data.paid_at',
net_amt number path '$.data.fees',
payment_type_id varchar2(500) path '$.data.fees',
transaction_type_id varchar2(500) path '$.data.fees',
payment_id varchar2(500) path '$.data.id',
payment_email varchar2(500) path '$.data.customer.email'
)
)
where status = 'done'
)
LOOP
p_amt := c.amount;
p_reference := c.reference;
p_name := c.type;
p_narration := c.narration;
p_payment_date := c.paid_at;
p_net_amt := c.net_amt;
p_payment_type_id := c.payment_type_id;
p_transaction_type_id := c.transaction_type_id;
p_payment_id := c.payment_id;
p_payment_email := c.payment_email;
select
id
into
p_user_id
from users where email = p_payment_email;
EXCEPTION
WHEN NO_DATA_FOUND
THEN
NULL;
WHEN OTHERS
THEN
RAISE;
dbms_output.put_line(p_user_id);
--update pstk_payload set status = 'done';
PAYMENT_PKG.add_payment(p_amt, p_user_id, p_reference, p_name, p_narration, p_payment_date, p_net_amt, p_payment_type_id, p_transaction_type_id, p_payment_id);
END LOOP;
end;
END;
You have:
BEGIN
DECLARE
<some variables>
BEGIN
FOR c IN (<some query>)
LOOP
<some stuff>
EXCEPTION
WHEN NO_DATA_FOUND
THEN
NULL;
WHEN OTHERS
THEN
RAISE;
<some more stuff>
END LOOP;
END;
END;
Inside the LOOP there is no BEGIN ... END that matches the exception.
Either:
put a BEGIN ... END inside the loop:
BEGIN
DECLARE
<some variables>
BEGIN
FOR c IN (<some query>)
LOOP
BEGIN
<some stuff>
EXCEPTION
WHEN NO_DATA_FOUND
THEN
NULL;
WHEN OTHERS
THEN
RAISE;
<some more stuff>
END;
END LOOP;
END;
END;
Or move the exception handling outside the loop:
BEGIN
DECLARE
<some variables>
BEGIN
FOR c IN (<some query>)
LOOP
<some stuff>
END LOOP;
EXCEPTION
WHEN NO_DATA_FOUND
THEN
NULL;
WHEN OTHERS
THEN
RAISE;
<some more stuff>
END;
END;
Once you fix that then you will get more errors as you cannot have SELECT .. INTO inside a cursor. Also, the <some more stuff> will never be run as you re-raise the exception before it.
Something like:
DECLARE
p_user_id USERS.ID%TYPE;
BEGIN
FOR c IN (
SELECT amount,
reference,
type,
narration,
paid_at,
net_amt,
payment_type_id,
transaction_type_id,
payment_id,
payment_email
FROM pstk_payload p
CROSS JOIN JSON_TABLE(
p.webhook_payload,
'$'
COLUMNS (
amount varchar2(500) path '$.data.amount',
reference varchar2(500) path '$.data.reference',
type varchar2(500) path '$.data.fees_breakdown.type',
narration varchar2(500) path '$.data.authorization.narration',
paid_at DATE path '$.data.paid_at',
net_amt number path '$.data.fees',
payment_type_id varchar2(500) path '$.data.fees',
transaction_type_id varchar2(500) path '$.data.fees',
payment_id varchar2(500) path '$.data.id',
payment_email varchar2(500) path '$.data.customer.email'
)
)
where status = 'done'
)
LOOP
BEGIN
select id
into p_user_id
from users
where email = c.payment_email;
EXCEPTION
WHEN NO_DATA_FOUND THEN
NULL;
WHEN OTHERS THEN
RAISE;
END;
dbms_output.put_line(p_user_id);
--update pstk_payload set status = 'done';
PAYMENT_PKG.add_payment(
c.amount,
p_user_id,
c.reference,
c.type,
c.narration,
c.paid_at,
c.net_amt,
c.payment_type_id,
c.transaction_type_id,
c.payment_id
);
END LOOP;
END;
/

raise Exception inside if condition in plsql

declare
cnt number;
begin
select count(*)
into cnt
FROM employee;
IF cnt = 0 THEN
DELETE employee;
COMMIT;
EXCEPTION
WHEN others THEN
log_error_local(k_sub_module, l_step||' '||sqlerrm);
raise;
END IF;
end
getting syntax error like below..
Error(188,13): PLS-00103: Encountered the symbol "EXCEPTION" when expecting one of the following: ( begin case declare else elsif 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
To fix your syntax issues, you can wrap the contents of the IF .. THEN statement in a BEGIN/END block:
DECLARE
cnt number;
BEGIN
select count(*)
into cnt
FROM employee;
IF cnt = 0 THEN
BEGIN
DELETE FROM employee;
COMMIT;
EXCEPTION
WHEN OTHERS THEN
log_error_local(k_sub_module, l_step||' '||sqlerrm);
raise;
END;
END IF;
END;
/
Note: the DELETE statement is missing the FROM keyword and you do not appear to have declared the k_sub_module or l_step variables.
or, since you are re-raising the exception and execution will be halted anyway, catch the exception outside the IF statement in the main block:
DECLARE
cnt number;
BEGIN
select count(*)
into cnt
FROM employee;
IF cnt = 0 THEN
DELETE FROM employee;
COMMIT;
END IF;
EXCEPTION
WHEN OTHERS THEN
log_error_local(k_sub_module, l_step||' '||sqlerrm);
raise;
END;
/
db<>fiddle here

character string buffer too small ORA-06502

I am having a problem while concatenating the varchar2 datatype in a cursor loop.
Procedure is iterating in a loop to build the in clause for insert and delete operations in batch.The process will run in batch for every 1000 account numbers.
For small amount of records it works but when it tries to concatenate large amount of records(36451477 in temp table) in a loop it throws.
java.sql.SQLException: ORA-06502: PL/SQL: numeric or value error:
character string buffer too small ORA-06512: at
"QA01BT.LOAD_ITEM_DATA_TO_CONSOLIDATE", line 23 ORA-06512: at line 1
i have put a max limit of search id to 32767 but still it does not work.
is there any other way to achieve this?
create or replace PROCEDURE LOAD_ITEM_DATA_TO_CONSOLIDATE(updatecount OUT NUMBER
)
IS
cnt NUMBER := 0;
c_limit CONSTANT PLS_INTEGER DEFAULT 1000;
search_id varchar2(32727);
TYPE account_array
IS TABLE OF VARCHAR2(255) INDEX BY BINARY_INTEGER;
l_data ACCOUNT_ARRAY;
CURSOR account_cursor IS
SELECT DISTINCT account_no AS account_num
FROM item_temp;
BEGIN
OPEN account_cursor;
LOOP
FETCH account_cursor bulk collect INTO l_data limit c_limit;
search_id := '''';
FOR i IN 1 .. l_data.count LOOP
IF( i != 1 ) THEN
search_id := search_id
|| ','
|| ''''
|| l_data(i)
|| '''';
ELSE
search_id := search_id
|| l_data(i)
|| '''';
END IF;
END LOOP;
BEGIN
SAVEPOINT move_data_to_temp_table;
EXECUTE IMMEDIATE 'delete from item where ACCOUNT_NO IN('||search_id||')';
EXECUTE IMMEDIATE 'insert into item(ID,ACCOUNT_NO,ITEM_ID,ITEM_VALUE) select HIBERNATE_SEQUENCE.nextval,temp.ACCOUNT_NO,temp.ITEM_ID,temp.ITEM_VALUE from item_TEMP temp where ACCOUNT_NO IN('||search_id||')';
cnt := cnt + SQL%rowcount;
COMMIT;
EXCEPTION WHEN OTHERS THEN ROLLBACK to move_data_to_temp_table;
END;
EXIT WHEN account_cursor%NOTFOUND;
END LOOP;
updatecount := cnt;
CLOSE account_cursor;
END LOAD_ITEM_DATA_TO_CONSOLIDATE;
This seems somewhat over-engineered. Why not just this?
create or replace PROCEDURE LOAD_ITEM_DATA_TO_CONSOLIDATE
(updatecount OUT NUMBER)
IS
BEGIN
delete from item
where ACCOUNT_NO IN ( SELECT account_no
FROM item_temp);
insert into item(ID,ACCOUNT_NO,ITEM_ID,ITEM_VALUE)
select HIBERNATE_SEQUENCE.nextval, temp.ACCOUNT_NO, temp.ITEM_ID, temp.ITEM_VALUE
from item_TEMP temp ;
updatecount := SQL%rowcount;
END LOAD_ITEM_DATA_TO_CONSOLIDATE;
If you do decide you need to do this in batches and are worried about that string getting too long or having too many elements in the list (max is 1000), you should try putting your values into an array and then using IN against the array, via a table function or a direct reference to the table.
Extra bonus: no need for dynamic SQL!
Something like this:
CREATE OR REPLACE TYPE strings_t IS TABLE OF VARCHAR2 (255)
/
CREATE OR REPLACE PROCEDURE load_item_data_to_consolidate (
updatecount OUT NUMBER)
IS
cnt NUMBER := 0;
c_limit CONSTANT PLS_INTEGER DEFAULT 1000;
l_data strings_t;
CURSOR account_cursor
IS
SELECT DISTINCT account_no AS account_num FROM item_temp;
BEGIN
OPEN account_cursor;
LOOP
FETCH account_cursor BULK COLLECT INTO l_data LIMIT c_limit;
BEGIN
SAVEPOINT move_data_to_temp_table;
DELETE FROM item
WHERE account_no IN (SELECT COLUMN_VALUE FROM TABLE (l_data));
INSERT INTO item (id,
account_no,
item_id,
item_value)
SELECT hibernate_sequence.NEXTVAL,
temp.account_no,
temp.item_id,
temp.item_value
FROM item_temp temp
WHERE account_no IN (SELECT COLUMN_VALUE FROM TABLE (l_data));
cnt := cnt + SQL%ROWCOUNT;
COMMIT;
EXCEPTION
WHEN OTHERS
THEN
ROLLBACK TO move_data_to_temp_table;
END;
EXIT WHEN account_cursor%NOTFOUND;
END LOOP;
END;

Variable in SQL -> ERROR PLS-00103: Encountered the symbol "SELECT"

How can iterate a variable in select? I receive a error
DECLARE
ESTACION_ID NUMBER(6) :=3;
BEGIN
SELECT
100*TOTAL_TAX_AMB1/(SELECT COUNT(*) FROM ITV2 WHERE ITV2.C_RESULTADO=1 AND ITV2.C_ESTACION_ID= ESTACION_ID ) AS TAXIS_Y_AMBULANCIAS_PRIMERA
...
END;
you can use a USING clause to bind a variable
DECLARE
ESTACION_ID NUMBER(6) :=3;
v_sql varchar2(32767);
BEGIN
v_sql := 'SELECT 100*TOTAL_TAX_AMB1/(SELECT COUNT(*) FROM ITV2 WHERE ITV2.C_RESULTADO=1 AND ITV2.C_ESTACION_ID= :1) AS TAXIS_Y_AMBULANCIAS_PRIMERA
...'
EXECUTE IMMEDIATE v_sql INTO ... USING ESTACION_ID;
END;

PL/SQL: ORA-00904: : invalid identifier

I am running the following SP but getting the error c1.pyid is invalid identifier. I am trying to use two different query results from one cursor. If there is any other way of using IF-else clause in a cursor, i am open to that too.
CREATE OR REPLACE
PROCEDURE FIX_DOCUMENT_RECORDS ( i_flag in varchar)
AS
Op_ID VARCHAR(8);
Op_Name VARCHAR(32);
skill VARCHAR(32);
temp_count VARCHAR(8);
temp_status VARCHAR(8):='Submitted';
QRYSTR VARCHAR2(400);
TYPE REF_CUR IS REF CURSOR;
c1 REF_CUR;
BEGIN
IF (i_flag='1') THEN
QRYSTR:='SELECT *
FROM dims_doc_master
WHERE concat_prod_id IS NULL
OR documenttypeid IS NULL
AND (pystatuswork = temp_status);';
ELSE
QRYSTR:='SELECT *
FROM dims_doc_master
WHERE (documentimageid IS NULL
AND p8id IS NULL)
AND (pystatuswork = temp_status);';
END IF;
open c1 FOR QRYSTR;
LOOP
BEGIN
DBMS_OUTPUT.PUT_LINE('loop begin');
UPDATE DIMS_DOC_MASTER
SET pystatuswork ='Cancelled',
documentstatus ='Cancelled',
cancellationdate='31-JAN-14',
cancelledbysid = c1.pxcreateoperator,
cancelreason ='Cancelled due to corruption.'
WHERE pyid =c1.pyid;
DBMS_OUTPUT.PUT_LINE('After updation'||c1.pyid );
--Begin PC_DOCUMENT UPDATION
UPDATE PC_DOCUMENT
SET pystatuswork ='Cancelled',
cancellationdate='31-JAN-14'
WHERE pyid =c1.pyid;
--Begin insert into History
--Select Operator name and ID
SELECT skill
INTO skill
FROM operator_map_skill
WHERE pyuseridentifier=c1.pxcreateoperator
AND rownum =1;
INSERT
INTO DIMS_DOC_HIST
(
DIMS_DOC_ID,
DOC_CHG_USR,
DOC_CHG_DT,
DOC_NEW_STS,
DOC_CHG_CMNT,
CRE_TS,
ROLE,
RSN_DESC,
TARGETROLE,
DOC_CHG_USR_ID,
DOC_ASG_USR_ID,
DOC_ASG_USR,
PREVSTATUS,
PREVSTATUSDT,
ASSIGNEDTODT,
TODISPLAY,
ACTIVITY_NAME
)
VALUES
(
c1.pyid,
'DIMS',
systimestamp,
'Cancelled',
'Cancelled due to corruption',
'31-JAN-14',
skill,
NULL,
skill,
c1.pxcreateoperator,
c1.pxcreateoperator,
c1.pxcreateopname,
'Submitted',
NULL,
systimestamp,
'Y',
'Updation through Script'
);
dbms_output.put_line
(
'Document ID= '||c1.pyid
)
;
SELECT COUNT(*)
INTO temp_count
FROM PC_ASSIGN_WORKBASKET
WHERE pxrefobjectinsname=c1.pyid;
IF(temp_count IS NOT NULL) THEN
DELETE FROM PC_ASSIGN_WORKBASKET WHERE pxrefobjectinsname=c1.pyid;
ELSE
DELETE FROM PC_ASSIGN_WORKLIST WHERE pxrefobjectinsname=c1.pyid;
END IF;
COMMIT;
END;
END LOOP;
CLOSE c1;
END;
You seem confusing cursor and fetched row.
In your current procedure: you open a cursor, do a loop (which looks to be endless since there is no EXIT statement), and after the loop you close the cursor (but it looks it will never happen)
To fetch results from a cursor, do the following:
CREATE OR REPLACE PROCEDURE ...
...
c1 REF_CUR;
ddm_record dims_doc_master%rowtype;
BEGIN
...
OPEN c1;
LOOP
FETCH c1 INTO ddm_record;
EXIT WHEN c1%NOTFOUND;
...
DBMS_OUTPUT.PUT_LINE('Document ID= ' || ddm_record.pyid); -- not c1.pyid
END LOOP;
CLOSE c1;
END;
/
Inspired from examples here: http://plsql-tutorial.com/plsql-explicit-cursors.htm
Try embedding the flag in your where clause:
open c1 FOR
SELECT *
FROM dims_doc_master
WHERE (i_flag='1' AND
(concat_prod_id IS NULL
OR documenttypeid IS NULL
AND (pystatuswork = temp_status))
OR (i_flag<>'1' AND
(documentimageid IS NULL
AND p8id IS NULL)
AND (pystatuswork = temp_status));
The logic can probably be simplified but logically that would work.