PL/SQL Continue exection after error handled - oracle

I'm newbie with PL/SQL and i've got the following situation.
In the following scritp i want that the script continue iterating if they found any exception. The exception are handled but I cannot execute the continue statement out of a loop.
declare
l_max_ID number;
l_Temp_val number;
type array_t is varray(135) of varchar2(30);
arrayTable array_t := array_t('YSXQTAAA', 'YSXQTAFA', ... );
array array_t := array_t('YSXQNAAA', 'YSXQNAFA', ...);
begin
dbms_output.put_line(arrayTable.count);
for i in 1..arrayTable.count loop
dbms_output.put_line('Tabla impactada ' || arrayTable(i));
execute immediate 'select max(id)+1 from ' || arrayTable(i) into l_max_ID;
execute immediate 'alter sequence ' || array(i) || ' restart start with ' || TO_CHAR(l_Max_ID);
dbms_output.put_line('alter sequence RS1.' || array(i) || ' restart start with ' || TO_CHAR(l_Max_ID));
end loop;
rollback;
EXCEPTION
WHEN NO_DATA_FOUND THEN
/* HAndle an error that gets raised when a query returns nothing */
dbms_output.put_line('Error 1');
WHEN TOO_MANY_ROWS THEN
/* HAndle the situation when too much data is returned such as with a select-into */
dbms_output.put_line('Error 2');
WHEN OTHERS THEN
dbms_output.put_line('Error 3');
end;
The problem is that some tables doesn't have id column and the select throw an exception. The array contains more than a hundred elements and delete each one takes a lot of time.

Put the exception handling block inside the loop:
begin
dbms_output.put_line(arrayTable.count);
for i in 1..arrayTable.count loop
begin
dbms_output.put_line('Tabla impactada ' || arrayTable(i));
execute immediate 'select max(id)+1 from ' || arrayTable(i) into l_max_ID;
execute immediate 'alter sequence ' || array(i) || ' restart start with ' || TO_CHAR(l_Max_ID);
dbms_output.put_line('alter sequence RS1.' || array(i) || ' restart start with ' || TO_CHAR(l_Max_ID));
EXCEPTION
WHEN NO_DATA_FOUND THEN
/* HAndle an error that gets raised when a query returns nothing */
dbms_output.put_line('Error 1');
continue;
WHEN TOO_MANY_ROWS THEN
/* HAndle the situation when too much data is returned such as with a select-into */
dbms_output.put_line('Error 2');
continue;
WHEN OTHERS THEN
dbms_output.put_line('Error 3');
continue;
end;
end loop;
rollback;
end;

Related

Trying to get the actual data that cause an exception

I have a procedure that takes an input of 2 Associative arrays and after some basic count checks, does a FORALL statement to insert the data into a table.
Here is the procedure:
PROCEDURE INSERT_RECS(P_PROD_TYP IN prod_type, P_PROD_ADD_PK IN prod_pk_type)
IS
uniq_key EXCEPTION;
PRAGMA EXCEPTION_INIT(uniq_key, -00001);
loc_cnt NUMBER;
BEGIN
IF P_PROD_TYP.COUNT = P_PROD_ADD_PK.COUNT THEN
FORALL i IN P_PROD_TYP.FIRST .. P_PROD_TYP.LAST
INSERT INTO product_table ( pk,
id,
created_by,
created_on,
last_chg_by,
last_chg_on)
VALUES (P_PROD_ADD_PK(i),
P_PROD_TYP(i).id,
P_PROD_TYP(i).created_by,
P_PROD_TYP(i).created_on,
NULL,
NULL);
END IF;
EXCEPTION
WHEN uniq_key THEN
loc_cnt := SQL%BULK_EXCEPTIONS.count;
FOR i IN 1 .. loc_cnt LOOP
dbms_output.put_line('EXCEPTION: Array Index: ' || SQL%BULK_EXCEPTIONS(i).error_index ||
' Message: ' || SQLERRM(-SQL%BULK_EXCEPTIONS(i).ERROR_CODE) ||
' SQLERRM: ' || SQLERRM ||
' SQLCODE: ' || SQLCODE ||
' stack: ' || SYS.dbms_utility.format_call_stack);
END LOOP;
RETURN;
END;
What I would like is if I hit an exception, is there a way that I could have view of the record that is causing the issue, essentially the index in the associative array or at least have the SQL% info have the info.
I have look at the following:
http://www.dba-oracle.com/plsql/t_plsql_exceptions.htm
but this outputs the info about the column but that is not what I am after.
Not sure if really answers your query but you can use the loop variable i in exception block to display the content of the exception array in your case. See below an example procedure:
CREATE OR REPLACE PROCEDURE PROC1 (V_EMP_ID DBMS_SQL.NUMBER_TABLE)
IS
lv_error_string VARCHAR2(4000);
BEGIN
FORALL INDX IN V_EMP_ID.FIRST..V_EMP_ID.LAST SAVE EXCEPTIONS
UPDATE EMPLOYEES
---trying to rasie an exception by using a calculation
SET SALARY=SALARY * 99999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999999
WHERE ID_E= V_EMP_ID(INDX);
EXCEPTION
WHEN OTHERS
THEN
FOR i IN 1 .. SQL%BULK_EXCEPTIONS.COUNT
LOOP
---Am printing the value of the exception array.
dbms_output.put_line('exception Raised for record' ||V_EMP_ID(i));
END LOOP;
END;
/
Ouput:
SQL> DECLARE
empid DBMS_SQL.NUMBER_TABLE;
BEGIN
empid (1) := 1;
empid (2) := 9;
PROC1 (empid);
END;
/
exception Raised for record 1
PL/SQL procedure successfully completed.

need to modify the below oracle query

I have the below script , i want to modify it such a way lets say if it is executed first time then it will create the column but lets say if it is executed second time then it will show fail message which is not correct it should show the message that column is created and also if there comes any exception lets say column i s not created due to some technical exception then it should show fail message , please advise how to achieve this
SELECT COUNT(*) INTO L_COL_EXISTS FROM USER_TAB_COLS WHERE COLUMN_NAME = 'TOR' and TABLE_NAME='AVOICE';
IF L_COL_EXISTS = 1
THEN
outcome := 'Success';
ELSE
outcome := 'Fail';
END IF;
DBMS_OUTPUT.PUT_LINE(outcome);
folks please advise
I suppose it can help you
CREATE OR REPLACE PROCEDURE add_column
(
v_table_name IN VARCHAR2,
v_column_name IN VARCHAR2,
v_column_type IN VARCHAR2
)
IS
v_column_exists pls_integer;
v_ddl_str varchar2(1024);
BEGIN
BEGIN
SELECT count(*)
INTO v_column_exists
FROM user_tab_columns
WHERE table_name = upper(v_table_name)
and column_name = upper(v_column_name);
EXCEPTION
WHEN OTHERS THEN
RAISE;
END;
if v_column_exists = 0 then
v_ddl_str := 'alter table ' || v_table_name || ' add ( ' || v_column_name || ' ' || v_column_type || ')';
BEGIN
EXECUTE IMMEDIATE alter_str;
EXCEPTION
WHEN OTHERS THEN
dbms_output.put_line ('something wrong');
RAISE;
END;
ELSE
dbms_output.put_line ('Column exists');
END IF;
EXCEPTION
WHEN OTHERS THEN
RAISE;
END add_column;
/

Stop stored procedure from running for all errors except ORA-00942 table does not exist

I have a stored procedure in Oracle 11g that will delete records for specific clients in some tables. The below script is an example of its set up. It will continue to run each block even if an exception is raised. We want it to stop running if any other exception occurs except "-942 table does not exist." If the table does not exist, the rest of the procedure should continue to run, all others should cause it to stop. How can I do this?
create or replace PROCEDURE SCHEMA.PURGE_RECORDS
(vCLIENT_ID IN VARCHAR2, pINPUTSCOPE IN VARCHAR2,
pSUCCESS_IND OUT VARCHAR2, pOUTCOME_DESC OUT VARCHAR2)
AS
VTABLE_NAME VARCHAR2(200);
vSQL VARCHAR2(10000);
BEGIN
IF pINPUTSCOPE = 'ALL' THEN
BEGIN
VTABLE_NAME := 'TABLE NAME';
vSQL := '
DELETE FROM TABLENAME T WHERE EXISTS (SELECT 1 FROM TABLE2 TSK WHERE CLIENT = '''|| vCLIENT_ID ||''' AND ASK_ID = T.ASK_ID) ';
EXECUTE IMMEDIATE vSQL;
DBMS_OUTPUT.PUT_LINE ( VTABLE_NAME || ' Scope set: ' || pINPUTSCOPE || ' ' || '(' || TO_CHAR(SQL%ROWCOUNT) || ' ROWS DELETED)' || chr(10));
EXCEPTION WHEN OTHERS THEN NULL; DBMS_OUTPUT.PUT_LINE('ERROR : ' || VTABLE_NAME || ' ' || SQLERRM);
END;
BEGIN
VTABLE_NAME := 'TABLE NAME';
vSQL := '
DELETE FROM TABLENAME3 T WHERE EXISTS (SELECT 1 FROM TABLE3 TSK WHERE CLIENT = '''|| vCLIENT_ID ||''' AND ASK_ID = T.ASK_ID) ';
EXECUTE IMMEDIATE vSQL;
DBMS_OUTPUT.PUT_LINE ( VTABLE_NAME || ' Scope set: ' || pINPUTSCOPE || ' ' || '(' || TO_CHAR(SQL%ROWCOUNT) || ' ROWS DELETED)' || chr(10));
EXCEPTION WHEN OTHERS THEN NULL; DBMS_OUTPUT.PUT_LINE('ERROR : ' || VTABLE_NAME || ' ' || SQLERRM);
END;
BEGIN
VTABLE_NAME := 'TABLE NAME';
vSQL := '
DELETE FROM TABLENAME4 T WHERE EXISTS (SELECT 1 FROM TABLE4 TSK WHERE CLIENT = '''|| vCLIENT_ID ||''' AND ASK_ID = T.ASK_ID) ';
EXECUTE IMMEDIATE vSQL;
DBMS_OUTPUT.PUT_LINE ( VTABLE_NAME || ' Scope set: ' || pINPUTSCOPE || ' ' || '(' || TO_CHAR(SQL%ROWCOUNT) || ' ROWS DELETED)' || chr(10));
EXCEPTION WHEN OTHERS THEN NULL; DBMS_OUTPUT.PUT_LINE('ERROR : ' || VTABLE_NAME || ' ' || SQLERRM);
END;
BEGIN
VTABLE_NAME := 'TABLE NAME';
vSQL := '
DELETE FROM TABLENAME5 T WHERE EXISTS (SELECT 1 FROM TABLE5 TSK WHERE CLIENT = '''|| vCLIENT_ID ||''' AND ASK_ID = T.ASK_ID) ';
EXECUTE IMMEDIATE vSQL;
DBMS_OUTPUT.PUT_LINE ( VTABLE_NAME || ' Scope set: ' || pINPUTSCOPE || ' ' || '(' || TO_CHAR(SQL%ROWCOUNT) || ' ROWS DELETED)' || chr(10));
EXCEPTION WHEN OTHERS THEN NULL; DBMS_OUTPUT.PUT_LINE('ERROR : ' || VTABLE_NAME || ' ' || SQLERRM);
END;
END IF;
END;
You can explicitly catch the ORA-00942 error, report it you want to, and then ignore it; and then either handle all other exceptions with a RAISE - which will propagate the exception to the next block, in this case causing the procedure to terminate - or don't catch them at all.
ORA-00942 isn't one of the predefined exceptions so you need to define an exception name and use the PRAGMA EXCEPTION_INIT clause to associate the exception to the internally defined exception number:
...
AS
VTABLE_NAME VARCHAR2(200);
vSQL VARCHAR2(10000);
NO_SUCH_TABLE EXCEPTION;
PRAGMA EXCEPTION_INIT (NO_SUCH_TABLE, -942);
BEGIN
IF pINPUTSCOPE = 'ALL' THEN
BEGIN
VTABLE_NAME := 'TABLE NAME';
vSQL := '
DELETE FROM TABLENAME T WHERE EXISTS (SELECT 1 FROM TABLE2 TSK WHERE CLIENT = '''|| vCLIENT_ID ||''' AND ASK_ID = T.ASK_ID) ';
EXECUTE IMMEDIATE vSQL;
DBMS_OUTPUT.PUT_LINE ( VTABLE_NAME || ' Scope set: ' || pINPUTSCOPE || ' ' || '(' || TO_CHAR(SQL%ROWCOUNT) || ' ROWS DELETED)' || chr(10));
EXCEPTION
WHEN NO_SUCH_TABLE THEN
DBMS_OUTPUT.PUT_LINE('ERROR : ' || VTABLE_NAME || ' ' || SQLERRM);
-- this exception has been squashed
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE('ERROR : ' || VTABLE_NAME || ' ' || SQLERRM);
RAISE;
END;
...
And repeat the exception catch in each sub-block. Any other exception will still be caught by your OTHERS handler. Catching and squashing OTHERS is generally a bad idea, and it would be better to remove that and let the exceptions propagate naturally; even though you're displaying the error (assuming whoever runs this is showing the output), you're losing the line number of the original problem. So you only really need to do:
...
EXECUTE IMMEDIATE vSQL;
DBMS_OUTPUT.PUT_LINE ( VTABLE_NAME || ' Scope set: ' || pINPUTSCOPE || ' ' || '(' || TO_CHAR(SQL%ROWCOUNT) || ' ROWS DELETED)' || chr(10));
EXCEPTION
WHEN NO_SUCH_TABLE THEN
DBMS_OUTPUT.PUT_LINE('ERROR : ' || VTABLE_NAME || ' ' || SQLERRM);
-- this exception has been squashed, all others will propagate
END;
...

Ora 01403 when try to insert data into oracle table

I have the following trigger
CREATE OR REPLACE TRIGGER L_BIUR_G_LAY
BEFORE INSERT OR UPDATE ON G_LAY
FOR EACH ROW
When (new.g_roo is not null)
DECLARE
x number(1);
stmt varchar(255);
BEGIN
FOR I IN (SELECT DISTINCT G_TAB FROM G_LEG)
LOOP
stmt := 'select distinct g_lind from ' || i.g_tab || ' where g_roo = ' || :new.g_roo;
Execute immediate stmt into x;
IF (x<>0) THEN
RAISE_APPLICATION_ERROR(-2001, 'G_ROO cannot be inserted where G_LIND IS NOT ZERO');
END IF;
END LOOP;
END;
/
and when I do
insert into G_LAY (G_OGCS, G_OGC, G_ROO, G_NM, G_TI, G_AB, G_DATE)
(select G_LAY_SEQ.NEXTVAL, 1, G_ROO, G_LGNDIT, G_UNE, 'Pipe Data Long - ' || G_UR, sysdate
from G_DTABLE where G_LIND = 0);
I get the following error
Error report:
SQL Error: ORA-01403: no data found
ORA-06512: at "L_BIUR_G_LAY", line 10
ORA-04088: error during execution of trigger 'G_LAY'
01403. 00000 - "no data found"
Any help would be greatly appreciated. It tried PRAGMA AUTONOMOUS_TRANSACTION after Declare in my trigger but it didn't help me
The problem is not with your INSERT statement. The problem occurs when the dynamically-built SELECT statement in the trigger is executed - no data is found so an ORA-01403 is raised. It looks to me like the easiest thing to do would be to do a SELECT COUNT(...):
CREATE OR REPLACE TRIGGER L_BIUR_G_LAY
BEFORE INSERT OR UPDATE ON G_LAY
FOR EACH ROW
When (new.g_rowno is not null)
DECLARE
x number;
stmt varchar(255);
BEGIN
FOR I IN (SELECT DISTINCT G_DISPCNTRLTAB FROM G_LEG) LOOP
stmt := 'select COUNT(*) from ' || i.g_dispcntrltab ||
' where g_rowno = ' || :new.g_rowno ||
' and g_lind <> 0';
Execute immediate stmt into x;
IF x <> 0 THEN
RAISE_APPLICATION_ERROR(-20001, 'G_RWNO cannot be inserted where G_LIND IS NOT ZERO');
END IF;
END LOOP;
END L_BIUR_G_LAY;
I also changed the error number which is raised as -2001 is not in the range of errors which can be raised using RAISE_APPLICATION_ERROR (the valid range is -20000 to -20999).
Share and enjoy.

Reset auto increment sequence pl-sql

How can i reset auto increment primary key ?
I have a doc_id_seq and a doc_pk_trg trigger like that:
CREATE SEQUENCE doc_id_seq START WITH 1;
CREATE OR REPLACE TRIGGER doc_pk_trg
BEFORE INSERT ON TFIDF FOR EACH ROW
BEGIN
IF :NEW.doc_id IS NULL THEN
SELECT doc_id_seq.NEXTVAL INTO :NEW.doc_id FROM DUAL;
END IF;
END;
/
I want to learn reset the sequence . How can I do this ?
You could use the ALTER SEQUENCE syntax.
Tom Kyte explains how to do exactly this here:
http://asktom.oracle.com/pls/asktom/f?p=100:11:0::::P11_QUESTION_ID:1119633817597
Simply drop and then recreate the sequence.
This is how I would reset it
CREATE OR REPLACE PROCEDURE reset_sequence (
p_sequence_name IN VARCHAR2,
p_new_value IN NUMBER
)
AS
l_current_value NUMBER;
v_sequence_exists NUMBER;
BEGIN
SELECT 1
INTO v_sequence_exists
FROM user_sequences
WHERE sequence_name = p_sequence_name;
EXECUTE IMMEDIATE 'SELECT ' || p_sequence_name || '.nextval FROM dual'
INTO l_current_value;
/*Not possible to increment by 0 !*/
IF (p_new_value - l_current_value - 1) != 0
THEN
EXECUTE IMMEDIATE 'ALTER SEQUENCE '
|| p_sequence_name
|| ' INCREMENT BY '
|| (p_new_value - l_current_value - 1)
|| ' MINVALUE 0';
END IF;
EXECUTE IMMEDIATE 'SELECT ' || p_sequence_name || '.nextval FROM dual'
INTO l_current_value;
EXECUTE IMMEDIATE 'ALTER SEQUENCE ' || p_sequence_name || ' INCREMENT BY 1 ';
EXCEPTION
WHEN NO_DATA_FOUND
THEN
raise_application_error (-20001, 'Sequence does not exist');
END;
This has the added benefit over drop & recreate of not invalidating any dependant schema objects.
try this
alter table "table_name"
modify "id" generated always as identity restart start with 1;

Resources