EXCEPTION HANDLE IN BULK COLLECT
HOW WILL I HANDLE EXCEPTION IN BULKCOLLECT
SUPPOSE IF NO DATA IS FOUND I WANT TO SET A VARIABLE IS 0 THEN THERE AFTER OTHER STAEMENT ARE PROCESSED
ELSE ALL STATEMENT ARE PROCESSED.
when you use bulk collect with select into, it doesn't raise any exception when no data is found. you can simple COUNT the elements in your array structure (in which you have collected the data) to check whether any rows have been processed or not.
like...
1 DECLARE
2 TYPE tt IS TABLE OF VARCHAR2(100) INDEX BY PLS_INTEGER;
3 v_tt tt;
4 BEGIN
5 SELECT ename BULK COLLECT INTO v_tt FROM emp WHERE empno = 7899;
6 DBMS_OUTPUT.PUT_LINE(v_tt.COUNT);
7* END;
11:43:37 SQL> /
0
PL/SQL procedure successfully completed.
Similar Messages
-
Exceptional handling using Bulk Collect FORALL
Hi Members,
Following are by DB details
SELECT * FROM v$version;
Oracle9i Enterprise Edition Release 9.2.0.7.0 - 64bit Production
PL/SQL Release 9.2.0.7.0 - Production
CORE 9.2.0.7.0 Production
TNS for HPUX: Version 9.2.0.7.0 - Production
NLSRTL Version 9.2.0.7.0 - ProductionI need to handle exception during Bulk Collect FORALL operation and update the table column with Status_flag as 'E' for given item name and extension id. Below is the code snippet for the same.
declare
k NUMBER;
cursor c_list_price
IS
SELECT /*+ leading(a) */ item_name,
'PUBLISH_TO_PRICE_CATALOG' ATTRIBUTE_NAME,
MAX(DECODE (attribute_name,
'PUBLISH_TO_PRICE_CATALOG',
attribute_value))
ATTRIBUTE_VALUE,
NULL GEOGRAPHY_LEVEL,
NULL GEOGRAPHY_VALUE,
NULL INCLUDE_GEOGRAPHY,
NULL EFFECTIVE_START_DATE,
NULL EFFECTIVE_TO_DATE,
EXTENSION_ID,
NULL PRICING_UNIT,
NULL ATTRIBUTE_FROM,
NULL ATTRIBUTE_TO,
NULL FIXED_BASE_PRICE,
NULL PARENT_ATTRIBUTE,
NULL DURATION_QUANTITY,
NULL ATTRIBUTE2,
NULL ATTRIBUTE3,
NULL ATTRIBUTE4,
NULL ATTRIBUTE5,
NULL ATTRIBUTE6,
NULL ATTRIBUTE7,
NULL ATTRIBUTE8,
NULL ATTRIBUTE9,
NULL ATTRIBUTE10,
NULL ATTRIBUTE11,
NULL ATTRIBUTE12,
NULL ATTRIBUTE13,
NULL ATTRIBUTE14,
NULL ATTRIBUTE15,
--ORG_CODE,
ITEM_CATALOG_CATEGORY ITEM_CATEGORY,
a.INVENTORY_ITEM_ID INVENTORY_ITEM_ID
FROM XXCPD_ITM_SEC_UDA_DETAILS_TB a
WHERE DECODE(attribute_group_name,'LIST_PRICE',DECODE(STATUS_FLAG,'E',1,'P',2,3)
,'XXITM_FORM_PRICING_HS',DECODE(STATUS_FLAG,'E',4,'P',5,6)
,'XXITM_FORM_PRICING_SB',DECODE(STATUS_FLAG,'E',4,'P',5,6)
,'XXITM_ADV_FORM_PRICING_HS',DECODE(STATUS_FLAG,'E',7,'P',8,9)
,'XXITM_ADV_FORM_PRICING_SB',DECODE(STATUS_FLAG,'E',7,'P',8,9)
,'XXITM_ADV_FORM_PRICING_HWSW',DECODE(STATUS_FLAG,'E',10,'P',11,12)
,'XXITM_ADV_FORM_PRICING_SWSUB',DECODE(STATUS_FLAG,'E',10,'P',11,12)
,'XXITM_ROUTE_TO_MARKET',DECODE(STATUS_FLAG,'E',13,'P',14,15)) in (1,2,3)
AND exists(select /*+ no_merge */ '1' from mtl_system_items_b b where a.inventory_item_id=b.inventory_item_id and b.organization_id=1)
GROUP BY item_name,
extension_id,
ITEM_CATALOG_CATEGORY,
INVENTORY_ITEM_ID;
TYPE myarray IS TABLE OF c_list_price%ROWTYPE;
c_lp myarray;
BEGIN
OPEN c_list_price;
LOOP
FETCH c_list_price BULK COLLECT INTO c_lp
LIMIT 50000;
IF c_lp.count = 0 THEN
EXIT;
END IF;
Begin
FORALL i IN c_lp.FIRST..c_lp.LAST SAVE EXCEPTIONS
INSERT /*+append*/ INTO XXCPD_ITEM_PRICING_ATTR_BKP2(
line_id,
ITEM_NAME,
ATTRIBUTE_NAME,
ATTRIBUTE_VALUE,
GEOGRAPHY_LEVEL,
GEOGRAPHY_VALUE,
INCLUDE_GEOGRAPHY,
EFFECTIVE_START_DATE,
EFFECTIVE_TO_DATE,
EXTENSION_ID,
PRICING_UNIT,
ATTRIBUTE_FROM,
ATTRIBUTE_TO,
FIXED_BASE_PRICE,
PARENT_ATTRIBUTE,
DURATION_QUANTITY,
ATTRIBUTE2,
ATTRIBUTE3,
ATTRIBUTE4,
ATTRIBUTE5,
ATTRIBUTE6,
ATTRIBUTE7,
ATTRIBUTE8,
ATTRIBUTE9,
ATTRIBUTE10,
ATTRIBUTE11,
ATTRIBUTE12,
ATTRIBUTE13,
ATTRIBUTE14,
ATTRIBUTE15,
ITEM_CATEGORY,
INVENTORY_ITEM_ID
VALUES
xxcpd.xxcpd_if_prc_line_id_s.NEXTVAL
,c_lp(i).ITEM_NAME
,c_lp(i).ATTRIBUTE_NAME
,c_lp(i).ATTRIBUTE_VALUE
,c_lp(i).GEOGRAPHY_LEVEL
,c_lp(i).GEOGRAPHY_VALUE
,c_lp(i).INCLUDE_GEOGRAPHY
,c_lp(i).EFFECTIVE_START_DATE
,c_lp(i).EFFECTIVE_TO_DATE
,c_lp(i).EXTENSION_ID
,c_lp(i).PRICING_UNIT
,c_lp(i).ATTRIBUTE_FROM
,c_lp(i).ATTRIBUTE_TO
,c_lp(i).FIXED_BASE_PRICE
,c_lp(i).PARENT_ATTRIBUTE
,c_lp(i).DURATION_QUANTITY
,c_lp(i).ATTRIBUTE2
,c_lp(i).ATTRIBUTE3
,c_lp(i).ATTRIBUTE4
,c_lp(i).ATTRIBUTE5
,c_lp(i).ATTRIBUTE6
,c_lp(i).ATTRIBUTE7
,c_lp(i).ATTRIBUTE8
,c_lp(i).ATTRIBUTE9
,c_lp(i).ATTRIBUTE10
,c_lp(i).ATTRIBUTE11
,c_lp(i).ATTRIBUTE12
,c_lp(i).ATTRIBUTE13
,c_lp(i).ATTRIBUTE14
,c_lp(i).ATTRIBUTE15
,c_lp(i).ITEM_CATEGORY
,c_lp(i).INVENTORY_ITEM_ID
EXCEPTION
WHEN OTHERS THEN
FOR j IN 1..SQL%bulk_exceptions.Count
LOOP
UPDATE XXCPD_ITM_SEC_UDA_DETAILS_TB
SET status_flag = 'E',
last_updated_by = 1,
last_update_date = SYSDATE
WHERE item_name = c_lp(SQL%BULK_EXCEPTIONS(j).ERROR_INDEX).item_name
AND extension_id=c_lp(SQL%BULK_EXCEPTIONS(j).ERROR_INDEX).extension_id;
COMMIT;
IF c_list_price%ISOPEN THEN
CLOSE c_list_price;
END IF;
FND_FILE.put_line(FND_FILE.output,'********************Exception Occured*************:-- '||SYSTIMESTAMP);
END LOOP;
END;
END LOOP;
CLOSE c_list_price;
COMMIT;
end;and I am getting following error
ORA-06550: line 156, column 47:
PL/SQL: ORA-00911: invalid character
ORA-06550: line 152, column 21:
PL/SQL: SQL Statement ignoredpointing to following lines in exception block for update clause.
WHERE item_name = c_lp(SQL%BULK_EXCEPTIONS(j).ERROR_INDEX).item_name
AND extension_id=c_lp(SQL%BULK_EXCEPTIONS(j).ERROR_INDEX).extension_id; can some one please help me out with the issue.
Thanks in AdvanceHave re-written the code in the following manner
declare
lv_ITEM_NAME DBMS_SQL.VARCHAR2S;
lv_ITEM_CATEGORY DBMS_SQL.VARCHAR2S;
lv_INVENTORY_ITEM_ID DBMS_SQL.NUMBER_TABLE;
lv_ATTRIBUTE_NAME DBMS_SQL.VARCHAR2S;
lv_ATTRIBUTE_VALUE DBMS_SQL.VARCHAR2S;
lv_GEOGRAPHY_LEVEL DBMS_SQL.VARCHAR2S;
lv_GEOGRAPHY_VALUE DBMS_SQL.VARCHAR2S;
lv_INCLUDE_GEOGRAPHY DBMS_SQL.VARCHAR2S;
lv_EFFECTIVE_START_DATE DBMS_SQL.date_table;
lv_EFFECTIVE_TO_DATE DBMS_SQL.date_table;
lv_EXTENSION_ID DBMS_SQL.NUMBER_TABLE;
lv_PRICING_UNIT DBMS_SQL.VARCHAR2S;
lv_ATTRIBUTE_FROM DBMS_SQL.VARCHAR2S;
lv_ATTRIBUTE_TO DBMS_SQL.VARCHAR2S;
lv_FIXED_BASE_PRICE DBMS_SQL.NUMBER_TABLE;
lv_PARENT_ATTRIBUTE DBMS_SQL.VARCHAR2S;
lv_DURATION_QUANTITY DBMS_SQL.NUMBER_TABLE;
lv_ATTRIBUTE2 DBMS_SQL.VARCHAR2S;
lv_ATTRIBUTE3 DBMS_SQL.VARCHAR2S;
lv_ATTRIBUTE4 DBMS_SQL.VARCHAR2S;
lv_ATTRIBUTE5 DBMS_SQL.VARCHAR2S;
lv_ATTRIBUTE6 DBMS_SQL.VARCHAR2S;
lv_ATTRIBUTE7 DBMS_SQL.VARCHAR2S;
lv_ATTRIBUTE8 DBMS_SQL.VARCHAR2S;
lv_ATTRIBUTE9 DBMS_SQL.VARCHAR2S;
lv_ATTRIBUTE10 DBMS_SQL.VARCHAR2S;
lv_ATTRIBUTE11 DBMS_SQL.VARCHAR2S;
lv_ATTRIBUTE12 DBMS_SQL.VARCHAR2S;
lv_ATTRIBUTE13 DBMS_SQL.VARCHAR2S;
lv_ATTRIBUTE14 DBMS_SQL.VARCHAR2S;
lv_ATTRIBUTE15 DBMS_SQL.VARCHAR2S;
l_item_name XXCPD_ITM_SEC_UDA_DETAILS_TB.item_name%TYPE;
l_extension_id XXCPD_ITM_SEC_UDA_DETAILS_TB.extension_id%TYPE;
cursor c_list_price
IS
SELECT /*+ leading(a) */ item_name,
'PUBLISH_TO_PRICE_CATALOG' ATTRIBUTE_NAME,
MAX(DECODE (attribute_name,
'PUBLISH_TO_PRICE_CATALOG',
attribute_value))
ATTRIBUTE_VALUE,
NULL GEOGRAPHY_LEVEL,
NULL GEOGRAPHY_VALUE,
NULL INCLUDE_GEOGRAPHY,
NULL EFFECTIVE_START_DATE,
NULL EFFECTIVE_TO_DATE,
EXTENSION_ID,
NULL PRICING_UNIT,
NULL ATTRIBUTE_FROM,
NULL ATTRIBUTE_TO,
NULL FIXED_BASE_PRICE,
NULL PARENT_ATTRIBUTE,
NULL DURATION_QUANTITY,
NULL ATTRIBUTE2,
NULL ATTRIBUTE3,
NULL ATTRIBUTE4,
NULL ATTRIBUTE5,
NULL ATTRIBUTE6,
NULL ATTRIBUTE7,
NULL ATTRIBUTE8,
NULL ATTRIBUTE9,
NULL ATTRIBUTE10,
NULL ATTRIBUTE11,
NULL ATTRIBUTE12,
NULL ATTRIBUTE13,
NULL ATTRIBUTE14,
NULL ATTRIBUTE15,
--ORG_CODE,
ITEM_CATALOG_CATEGORY ITEM_CATEGORY,
a.INVENTORY_ITEM_ID INVENTORY_ITEM_ID
FROM XXCPD_ITM_SEC_UDA_DETAILS_TB a
WHERE DECODE(attribute_group_name,'LIST_PRICE',DECODE(STATUS_FLAG,'E',1,'P',2,3)
,'XXITM_FORM_PRICING_HS',DECODE(STATUS_FLAG,'E',4,'P',5,6)
,'XXITM_FORM_PRICING_SB',DECODE(STATUS_FLAG,'E',4,'P',5,6)
,'XXITM_ADV_FORM_PRICING_HS',DECODE(STATUS_FLAG,'E',7,'P',8,9)
,'XXITM_ADV_FORM_PRICING_SB',DECODE(STATUS_FLAG,'E',7,'P',8,9)
,'XXITM_ADV_FORM_PRICING_HWSW',DECODE(STATUS_FLAG,'E',10,'P',11,12)
,'XXITM_ADV_FORM_PRICING_SWSUB',DECODE(STATUS_FLAG,'E',10,'P',11,12)
,'XXITM_ROUTE_TO_MARKET',DECODE(STATUS_FLAG,'E',13,'P',14,15)) in (1,2,3)
AND exists(select /*+ no_merge */ '1' from mtl_system_items_b b where a.inventory_item_id=b.inventory_item_id and b.organization_id=1)
GROUP BY item_name,
extension_id,
ITEM_CATALOG_CATEGORY,
INVENTORY_ITEM_ID;
BEGIN
OPEN c_list_price;
LOOP
lv_ITEM_NAME.delete;
lv_ITEM_CATEGORY.delete;
lv_INVENTORY_ITEM_ID.delete;
lv_ATTRIBUTE_NAME.delete;
lv_ATTRIBUTE_VALUE.delete;
lv_GEOGRAPHY_LEVEL.delete;
lv_GEOGRAPHY_VALUE.delete;
lv_INCLUDE_GEOGRAPHY.delete;
lv_EFFECTIVE_START_DATE.delete;
lv_EFFECTIVE_TO_DATE.delete;
lv_EXTENSION_ID.delete;
lv_PRICING_UNIT.delete;
lv_ATTRIBUTE_FROM.delete;
lv_ATTRIBUTE_TO.delete;
lv_FIXED_BASE_PRICE.delete;
lv_PARENT_ATTRIBUTE.delete;
lv_DURATION_QUANTITY.delete;
lv_ATTRIBUTE2.delete;
lv_ATTRIBUTE3.delete;
lv_ATTRIBUTE4.delete;
lv_ATTRIBUTE5.delete;
lv_ATTRIBUTE6.delete;
lv_ATTRIBUTE7.delete;
lv_ATTRIBUTE8.delete;
lv_ATTRIBUTE9.delete;
lv_ATTRIBUTE10.delete;
lv_ATTRIBUTE11.delete;
lv_ATTRIBUTE12.delete;
lv_ATTRIBUTE13.delete;
lv_ATTRIBUTE14.delete;
lv_ATTRIBUTE15.delete;
FETCH c_list_price BULK COLLECT INTO lv_ITEM_NAME
,lv_ATTRIBUTE_NAME
,lv_ATTRIBUTE_VALUE
,lv_GEOGRAPHY_LEVEL
,lv_GEOGRAPHY_VALUE
,lv_INCLUDE_GEOGRAPHY
,lv_EFFECTIVE_START_DATE
,lv_EFFECTIVE_TO_DATE
,lv_EXTENSION_ID
,lv_PRICING_UNIT
,lv_ATTRIBUTE_FROM
,lv_ATTRIBUTE_TO
,lv_FIXED_BASE_PRICE
,lv_PARENT_ATTRIBUTE
,lv_DURATION_QUANTITY
,lv_ATTRIBUTE2
,lv_ATTRIBUTE3
,lv_ATTRIBUTE4
,lv_ATTRIBUTE5
,lv_ATTRIBUTE6
,lv_ATTRIBUTE7
,lv_ATTRIBUTE8
,lv_ATTRIBUTE9
,lv_ATTRIBUTE10
,lv_ATTRIBUTE11
,lv_ATTRIBUTE12
,lv_ATTRIBUTE13
,lv_ATTRIBUTE14
,lv_ATTRIBUTE15
,lv_ITEM_CATEGORY
,lv_INVENTORY_ITEM_ID
LIMIT 50000;
IF lv_INVENTORY_ITEM_ID.count = 0 THEN
EXIT;
END IF;
Begin
FORALL I IN 1..lv_INVENTORY_ITEM_ID.count SAVE EXCEPTIONS
INSERT /*+append*/ INTO XXCPD_ITEM_PRICING_ATTR_BKP2(
line_id,
ITEM_NAME,
ATTRIBUTE_NAME,
ATTRIBUTE_VALUE,
GEOGRAPHY_LEVEL,
GEOGRAPHY_VALUE,
INCLUDE_GEOGRAPHY,
EFFECTIVE_START_DATE,
EFFECTIVE_TO_DATE,
EXTENSION_ID,
PRICING_UNIT,
ATTRIBUTE_FROM,
ATTRIBUTE_TO,
FIXED_BASE_PRICE,
PARENT_ATTRIBUTE,
DURATION_QUANTITY,
ATTRIBUTE2,
ATTRIBUTE3,
ATTRIBUTE4,
ATTRIBUTE5,
ATTRIBUTE6,
ATTRIBUTE7,
ATTRIBUTE8,
ATTRIBUTE9,
ATTRIBUTE10,
ATTRIBUTE11,
ATTRIBUTE12,
ATTRIBUTE13,
ATTRIBUTE14,
ATTRIBUTE15,
ITEM_CATEGORY,
INVENTORY_ITEM_ID
VALUES
xxcpd.xxcpd_if_prc_line_id_s.NEXTVAL
,lv_ITEM_NAME(i)
,lv_ATTRIBUTE_NAME(i)
,lv_ATTRIBUTE_VALUE(i)
,lv_GEOGRAPHY_LEVEL(i)
,lv_GEOGRAPHY_VALUE(i)
,lv_INCLUDE_GEOGRAPHY(i)
,lv_EFFECTIVE_START_DATE(i)
,lv_EFFECTIVE_TO_DATE(i)
,lv_EXTENSION_ID(i)
,lv_PRICING_UNIT(i)
,lv_ATTRIBUTE_FROM(i)
,lv_ATTRIBUTE_TO(i)
,lv_FIXED_BASE_PRICE(i)
,lv_PARENT_ATTRIBUTE(i)
,lv_DURATION_QUANTITY(i)
,lv_ATTRIBUTE2(i)
,lv_ATTRIBUTE3(i)
,lv_ATTRIBUTE4(i)
,lv_ATTRIBUTE5(i)
,lv_ATTRIBUTE6(i)
,lv_ATTRIBUTE7(i)
,lv_ATTRIBUTE8(i)
,lv_ATTRIBUTE9(i)
,lv_ATTRIBUTE10(i)
,lv_ATTRIBUTE11(i)
,lv_ATTRIBUTE12(i)
,lv_ATTRIBUTE13(i)
,lv_ATTRIBUTE14(i)
,lv_ATTRIBUTE15(i)
,lv_ITEM_CATEGORY(i)
,lv_INVENTORY_ITEM_ID(i)
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
FOR j IN 1..SQL%bulk_exceptions.Count
LOOP
l_item_name:=lv_ITEM_NAME(SQL%BULK_EXCEPTIONS(j).ERROR_INDEX);
l_extension_id:=lv_EXTENSION_ID(SQL%BULK_EXCEPTIONS(j).ERROR_INDEX);
UPDATE XXCPD_ITM_SEC_UDA_DETAILS_TB
SET status_flag = 'E',
last_updated_by = 1,
last_update_date = SYSDATE
WHERE item_name = l_item_name
AND extension_id=l_extension_id;
COMMIT;
FND_FILE.put_line(FND_FILE.output,'********************Exception Occured*************:-- '||SYSTIMESTAMP);
END LOOP;
END;
END LOOP;
CLOSE c_list_price;
COMMIT;
end; -
How to handle multiple save exceptions (Bulk Collect)
Hi
How to handle Multiple Save exceptions? Is it possible to rollback to first deletion(of child table) took place in the procedure.
There are 3 tables
txn_header_interface(Grand Parent)
orders(parent)
order_items (Child)
One transaction can have one or multiple orders in it.
and one orders can have one or multiple order_items in it.
We need to delete the data from child table first then its parent and then from the grand parent table.if some error occurs anywhere I need to rollback to child record deletion. Since there is flag in child table which tells us when to delete data from database.
Is it possible to give name to Save exceptions?
e.g.
FORALL i IN ABC.FIRST..ABC.LAST SAVE EXCEPTIONS A
FORALL i IN abc.FIRST..ABC.LAST SAVE EXCEPTIONS B
if some error occurs then
ROLLBACK A; OR ROLLBACK B;
Please find the procedure attached
How to handle the errors with Save exception and rollback upto child table deletion.
CREATE OR REPLACE
PROCEDURE DELETE_CONFIRMED_DATA IS
TYPE TXN_HDR_INFC_ID IS TABLE OF TXN_HEADER_INTERFACE.ID%TYPE;
TXN_HDR_INFC_ID_ARRAY TXN_HDR_INFC_ID;
ERROR_COUNT NUMBER;
BULK_ERRORS EXCEPTION;
PRAGMA exception_init(bulk_errors, -24381);
BEGIN
SELECT THI.ID BULK COLLECT
INTO TXN_HDR_INFC_ID_ARRAY
FROM TXN_HEADER_INTERFACE THI,ORDERS OS,ORDER_ITEMS OI
WHERE THI.ID = OS.TXN_HDR_INFC_ID
AND OS.ID = OI.ORDERS_ID
AND OI.POSTING_ITEM_ID = VPI.ID
OI.DW_STATUS_FLAG =4 --data is moved to Datawarehouse
MINUS
(SELECT THI.ID FROM TXN_HEADER_INTERFACE THI,ORDERS OS,ORDER_ITEMS OI
WHERE THI.ID = OS.TXN_HDR_INFC_ID
AND OS.ID = OI.ORDERS_ID
OI.DW_STATUS_FLAG !=4);
IF SQL%NOTFOUND
THEN
EXIT;
END IF;
FORALL i IN TXN_HDR_INFC_ID_ARRAY.FIRST..TXN_HDR_INFC_ID_ARRAY.LAST SAVE
EXCEPTIONS
DELETE FROM ORDER_ITEMS OI
WHERE OI.ID IN (SELECT OI.ID FROM ORDER_ITEMS OI,ORDERS
OS,TXN_HEADER_INTERFACE THI
WHERE OS.ID = OI.ORDERS_ID
AND OS.TXN_HDR_INFC_ID = THI.ID
AND THI.ID = TXN_HDR_INFC_ID_ARRAY(i));
FORALL i IN TXN_HDR_INFC_ID_ARRAY.FIRST..TXN_HDR_INFC_ID_ARRAY.LAST SAVE
EXCEPTIONS
DELETE FROM ORDERS OS
WHERE OS.ID IN (SELECT OS.ID FROM ORDERS OS,TXN_HEADER_INTERFACE THI
WHERE OS.TXN_HDR_INFC_ID = THI.ID
AND THI.ID = TXN_HDR_INFC_ID_ARRAY(i));
FORALL i IN TXN_HDR_INFC_ID_ARRAY.FIRST..TXN_HDR_INFC_ID_ARRAY.LAST SAVE
EXCEPTIONS
DELETE FROM TXN_HEADER_INTERFACE THI
WHERE THI.ID = TXN_HDR_INFC_ID_ARRAY(i);
COMMIT;
DBMS_OUTPUT.PUT_LINE(TO_CHAR(SYSDATE, 'DD-MON-YY HH:MIPM')||':
DELETE_CONFIRMED_DATA: INFO:DELETION SUCCESSFUL');
EXCEPTION
WHEN OTHERS THEN
ERROR_COUNT := SQL%BULK_EXCEPTIONS.COUNT;
DBMS_OUTPUT.PUT_LINE(TO_CHAR(SYSDATE, 'DD-MON-YY HH:MIPM')||':
DELETE_CONFIRMED_DATA: ERROR:Number of errors is ' ||ERROR_COUNT);
FOR indx IN 1..ERROR_COUNT LOOP
DBMS_OUTPUT.PUT_LINE('Error ' || indx || 'occurred during
'||'iteration'||SQL%BULK_EXCEPTIONS(indx).ERROR_INDEX);
DBMS_OUTPUT.PUT_LINE('Error is '
||SQLERRM(-SQL%BULK_EXCEPTIONS(indx).ERROR_CODE));
END LOOP;
END DELETE_CONFIRMED_DATA;
Any suggestion would be of great help.
Thanks in advance
AnuIf you have one or two places in your code that need multiple exceptions, just do it with multiple catch statements. Unless you are trying to write the most compact Programming 101 homework program, inventing tricks to remove two lines of code is not good use of your time.
If you have multiple catches all over your code it could be a code smell. You may have too much stuff happening inside one try statement. It becomes hard to know what method call throws one of those exceptions, and you end up handling an exception from some else piece of code than what you intended. E.g. you mention NumberFormatException -- only process one user input inside that try/catch so it is easy to see what error message is given if that particular input is gunk. The next step of processing goes inside its own try/catch.
In my case, the ArrayIndexOutOfBoundsException and
NumberFormatException should be handled by the same way.Why?
I don't think I have ever seen an ArrayIndexOutOfBoundsException that didn't indicate a bug in the code. Instead of an AIOOBE perhaps there should be an if statement somewhere that prevents it, or the algorithm logic should prevent it automatically. -
Handling exception in BULK COLLECT
Hi Experts,
For the following procedure if
I send the existed employee number of emp table as input
the procedure is executing successfully.
But if I send the employee number as input which does not exist in the emp table
the exection block does not handling the exception.
I am geeting the following error.
ORA-06502: PL/SQL: numeric or value error
ORA-06512: at "RAKULA.SP_TEST_EXCEPTION_BULK", line 8
ORA-06512: at line 7If I use WHEN OTHERS exception then I am able to handle that exception.
Why it's happening like this.
Please explain me.
CREATE OR REPLACE PROCEDURE RAKULA.sp_test_exception_bulk(i_empno NUMBER)
IS
t type_test1;
BEGIN
SELECT deptno BULK COLLECT INTO t
FROM emp
WHERE empno=i_empno;
FOR indx IN t.FIRST..t.LAST
loop
dbms_output.put_line(t(indx));
end loop;
EXCEPTION
WHEN NO_DATA_FOUND THEN
dbms_output.put_line('employee number' ||i_empno|| 'does not exist');
END sp_test_exception_bulk;
/Please help me how to handle that exception.
If I create the procedure without using
BULK COLLECT then I am able to handle that exception using WHEN NO_DATA_FOUND
In the following procedure I am able to handle the exception.
CREATE OR REPLACE PROCEDURE RAKULA.sp_test_exception(i_empno NUMBER,v_dept_no OUT NUMBER)
IS
BEGIN
SELECT deptno INTO v_dept_no FROM emp
WHERE empno=i_empno;
EXCEPTION
WHEN NO_DATA_FOUND THEN
dbms_output.put_line('employee number' ||i_empno|| 'does not exist');
END sp_test_exception;
/user9077483 wrote:
Hi Experts,
For the following procedure if
I send the existed employee number of emp table as input
the procedure is executing successfully.
But if I send the employee number as input which does not exist in the emp table
the exection block does not handling the exception.
I am geeting the following error.
ORA-06502: PL/SQL: numeric or value error
ORA-06512: at "RAKULA.SP_TEST_EXCEPTION_BULK", line 8
ORA-06512: at line 7If I use WHEN OTHERS exception then I am able to handle that exception.
Why it's happening like this.
Please explain me.
CREATE OR REPLACE PROCEDURE RAKULA.sp_test_exception_bulk(i_empno NUMBER)
IS
t type_test1;
BEGIN
SELECT deptno BULK COLLECT INTO t
FROM emp
WHERE empno=i_empno;
FOR indx IN t.FIRST..t.LAST
loop
dbms_output.put_line(t(indx));
end loop;
EXCEPTION
WHEN NO_DATA_FOUND THEN
dbms_output.put_line('employee number' ||i_empno|| 'does not exist');
END sp_test_exception_bulk;
/Please help me how to handle that exception.
If I create the procedure without using
BULK COLLECT then I am able to handle that exception using WHEN NO_DATA_FOUND
In the following procedure I am able to handle the exception.
CREATE OR REPLACE PROCEDURE RAKULA.sp_test_exception(i_empno NUMBER,v_dept_no OUT NUMBER)
IS
BEGIN
SELECT deptno INTO v_dept_no FROM emp
WHERE empno=i_empno;
EXCEPTION
WHEN NO_DATA_FOUND THEN
dbms_output.put_line('employee number' ||i_empno|| 'does not exist');
END sp_test_exception;
The reason your Previous procedure does not execute completely is because you have handled only NO_DATA_FOUND exception, but the system generated
ORA-06502: PL/SQL: numeric or value error
ORA-06512: at "RAKULA.SP_TEST_EXCEPTION_BULK", line 8
ORA-06512: at line 7You will have to handle VALUE_ERROR exception in addition to NO_DATA_FOUND.
If you could tell us the Type of Collection "t", it would be helpful. What is the datatype of Dept column and the collection "t"?
Read this for PL/SQL predefined Exceptions. -
How to handle the bad record while using bulk collect with limit.
Hi
How to handle the Bad record as part of the insertion/updation to avoid the transaction.
Example:
I am inserting into table with LIMIT of 1000 records and i've got error at 588th record.
i want to commit the transaction with 588 inserted record in table and log the error into
error logging table then i've to continue with transaction with 560th record.
Can anyone suggest me in this case.
Regards,
yuva>
How to handle the Bad record as part of the insertion/updation to avoid the transaction.
>
Use the SAVE EXCEPTIONS clause of the FORALL if you are doing bulk inserts.
See SAVE EXCEPTIONS in the PL/SQL Language doc
http://docs.oracle.com/cd/B28359_01/appdev.111/b28370/tuning.htm
And then see Example 12-9 Bulk Operation that continues despite exceptions
>
Example 12-9 Bulk Operation that Continues Despite Exceptions
-- Temporary table for this example:
CREATE TABLE emp_temp AS SELECT * FROM employees;
DECLARE
TYPE empid_tab IS TABLE OF employees.employee_id%TYPE;
emp_sr empid_tab;
-- Exception handler for ORA-24381:
errors NUMBER;
dml_errors EXCEPTION;
PRAGMA EXCEPTION_INIT(dml_errors, -24381);
BEGIN
SELECT employee_id
BULK COLLECT INTO emp_sr FROM emp_temp
WHERE hire_date < '30-DEC-94';
-- Add '_SR' to job_id of most senior employees:
FORALL i IN emp_sr.FIRST..emp_sr.LAST SAVE EXCEPTIONS
UPDATE emp_temp SET job_id = job_id || '_SR'
WHERE emp_sr(i) = emp_temp.employee_id;
-- If errors occurred during FORALL SAVE EXCEPTIONS,
-- a single exception is raised when the statement completes.
EXCEPTION
-- Figure out what failed and why
WHEN dml_errors THEN
errors := SQL%BULK_EXCEPTIONS.COUNT;
DBMS_OUTPUT.PUT_LINE
('Number of statements that failed: ' || errors);
FOR i IN 1..errors LOOP
DBMS_OUTPUT.PUT_LINE('Error #' || i || ' occurred during '||
'iteration #' || SQL%BULK_EXCEPTIONS(i).ERROR_INDEX);
DBMS_OUTPUT.PUT_LINE('Error message is ' ||
SQLERRM(-SQL%BULK_EXCEPTIONS(i).ERROR_CODE));
END LOOP;
END;
DROP TABLE emp_temp; -
SAVE EXCEPTIONS when fetching from cursors by BULK COLLECT possible?
Oracle Database 10g Enterprise Edition Release 10.2.0.4.0 - 64bit Production
Hello,
I'm using an Cursor's FETCH by BULK COLLECT INTO mydata...
Is it possible to SAVE EXCEPTIONS like with FORALL? Or is there any other possibility to handle exceptions during bulk-fetches?
Regards,
MartinThe cursor's SELECT-statement uses TO_DATE(juldat,'J')-function (for converting an julian date value to DATE), but some rows contain an invalid juldat-value (leading to ORA-01854).
I want to handle this "rows' exceptions" like in FORALL.
But it could also be any other (non-Oracle/self-made) function within "any" BULK instruction raising (un)wanted exceptions... how can I handle these ones?
Martin -
How do you use exception in BULK FETCH?
<How do you use exception in BULK FETCH?>
I've never gotten an exception in a bulk fetch, aside from getting the error when the query select list does not match the variables its being selected into. I think that normal exception handling would apply.
I'm assuming you mean BULK COLLECTS. Did you mean bulk binds, the FORALL statement? -
Utl_file - exception handling when inserted in bulk.
Hi,
I am using Oracle 10gR2. I wanted to write data to a file. Due to huge number of records, I am collecting them into a collection, traversing e collection, appending the values in collection to a varchar variable with new line in a loop.If the array size is say 50, I will have 50 values in the Vatchar variable separated by CHR(10). and I will insert the variable using UTL_FILE.PUT so that 50 lines will be inserted with values into the file.
Now my query is if any one among those 50 values gives an exception, I feel all the 50 values can't be loaded. Please suggest exception handling in this case.
Regards,
Naveen Kumar.C.
Edited by: Naveen Kumar C on Sep 17, 2009 5:23 PMYou could use a CLOB in conjunction with UTL_FILE to write it out 32K at a time...
SQL> ed
Wrote file afiedt.buf
1 DECLARE
2 l_file UTL_FILE.FILE_TYPE;
3 l_clob CLOB;
4 l_buffer VARCHAR2(32767);
5 l_amount BINARY_INTEGER := 32767;
6 l_pos INTEGER := 1;
7 BEGIN
8 BEGIN
9 SELECT dbms_xmlgen.getxmltype('select * from emp natural join dept').getclobval()
10 INTO l_clob
11 FROM dual;
12 EXCEPTION
13 WHEN NO_DATA_FOUND THEN
14 RETURN;
15 END;
16 l_file := UTL_FILE.fopen('TEST_DIR', 'Sample2.txt', 'w', 32767);
17 LOOP
18 DBMS_LOB.read (l_clob, l_amount, l_pos, l_buffer);
19 UTL_FILE.put(l_file, l_buffer);
20 l_pos := l_pos + l_amount;
21 END LOOP;
22 EXCEPTION
23 WHEN NO_DATA_FOUND THEN -- occurs when end of CLOB reached
24 UTL_FILE.fclose(l_file);
25 WHEN OTHERS THEN
26 DBMS_OUTPUT.put_line(SQLERRM);
27 UTL_FILE.fclose(l_file);
28* END;
SQL> /
PL/SQL procedure successfully completed.
SQL> -
Hi all,
I have a performance issue in the below code,where i am trying to insert the data from table_stg into target_tab and in parent_tab tables and then to child tables via cursor with bulk collect .the target_tab and parent_tab are huge tables and have a row wise trigger enabled on it .the trigger is mandatory . This timetaken for this block to execute is 5000 seconds.Now my requirement is to reduce it to 5 to 10 mins.
can someone please guide me here.Its bit urgent .Awaiting for your response.
declare
vmax_Value NUMBER(5);
vcnt number(10);
id_val number(20);
pc_id number(15);
vtable_nm VARCHAR2(100);
vstep_no VARCHAR2(10);
vsql_code VARCHAR2(10);
vsql_errm varchar2(200);
vtarget_starttime timestamp;
limit_in number :=10000;
idx number(10);
cursor stg_cursor is
select
DESCRIPTION,
SORT_CODE,
ACCOUNT_NUMBER,
to_number(to_char(CORRESPONDENCE_DATE,'DD')) crr_day,
to_char(CORRESPONDENCE_DATE,'MONTH') crr_month,
to_number(substr(to_char(CORRESPONDENCE_DATE,'DD-MON-YYYY'),8,4)) crr_year,
PARTY_ID,
GUID,
PAPERLESS_REF_IND,
PRODUCT_TYPE,
PRODUCT_BRAND,
PRODUCT_HELD_ID,
NOTIFICATION_PREF,
UNREAD_CORRES_PERIOD,
EMAIL_ID,
MOBILE_NUMBER,
TITLE,
SURNAME,
POSTCODE,
EVENT_TYPE,
PRIORITY_IND,
SUBJECT,
EXT_PRD_ID_TX,
EXT_PRD_HLD_ID_TX,
EXT_SYS_ID,
EXT_PTY_ID_TX,
ACCOUNT_TYPE_CD,
COM_PFR_TYP_TX,
COM_PFR_OPT_TX,
COM_PFR_RSN_CD
from table_stg;
type rec_type is table of stg_rec_type index by pls_integer;
v_rt_all_cols rec_type;
BEGIN
vstep_no := '0';
vmax_value := 0;
vtarget_starttime := systimestamp;
id_val := 0;
pc_id := 0;
success_flag := 0;
vstep_no := '1';
vtable_nm := 'before cursor';
OPEN stg_cursor;
vstep_no := '2';
vtable_nm := 'After cursor';
LOOP
vstep_no := '3';
vtable_nm := 'before fetch';
--loop
FETCH stg_cursor BULK COLLECT INTO v_rt_all_cols LIMIT limit_in;
vstep_no := '4';
vtable_nm := 'after fetch';
--EXIT WHEN v_rt_all_cols.COUNT = 0;
EXIT WHEN stg_cursor%NOTFOUND;
FOR i IN 1 .. v_rt_all_cols.COUNT
LOOP
dbms_output.put_line(upper(v_rt_all_cols(i).event_type));
if (upper(v_rt_all_cols(i).event_type) = upper('System_enforced')) then
vstep_no := '4.1';
vtable_nm := 'before seq sel';
select PC_SEQ.nextval into pc_id from dual;
vstep_no := '4.2';
vtable_nm := 'before insert corres';
INSERT INTO target1_tab
(ID,
PARTY_ID,
PRODUCT_BRAND,
SORT_CODE,
ACCOUNT_NUMBER,
EXT_PRD_ID_TX,
EXT_PRD_HLD_ID_TX,
EXT_SYS_ID,
EXT_PTY_ID_TX,
ACCOUNT_TYPE_CD,
COM_PFR_TYP_TX,
COM_PFR_OPT_TX,
COM_PFR_RSN_CD,
status)
VALUES
(pc_id,
v_rt_all_cols(i).party_id,
decode(v_rt_all_cols(i).product_brand,'LTB',2,'HLX',1,'HAL',1,'BOS',3,'VER',4,0),
v_rt_all_cols(i).sort_code,
'XXXX'||substr(trim(v_rt_all_cols(i).ACCOUNT_NUMBER),length(trim(v_rt_all_cols(i).ACCOUNT_NUMBER))-3,4),
v_rt_all_cols(i).EXT_PRD_ID_TX,
v_rt_all_cols(i).EXT_PRD_HLD_ID_TX,
v_rt_all_cols(i).EXT_SYS_ID,
v_rt_all_cols(i).EXT_PTY_ID_TX,
v_rt_all_cols(i).ACCOUNT_TYPE_CD,
v_rt_all_cols(i).COM_PFR_TYP_TX,
v_rt_all_cols(i).COM_PFR_OPT_TX,
v_rt_all_cols(i).COM_PFR_RSN_CD,
NULL);
vstep_no := '4.3';
vtable_nm := 'after insert corres';
else
select COM_SEQ.nextval into id_val from dual;
vstep_no := '6';
vtable_nm := 'before insertcomm';
if (upper(v_rt_all_cols(i).event_type) = upper('REMINDER')) then
vstep_no := '6.01';
vtable_nm := 'after if insertcomm';
insert into parent_tab
(ID ,
CTEM_CODE,
CHA_CODE,
CT_CODE,
CONTACT_POINT_ID,
SOURCE,
RECEIVED_DATE,
SEND_DATE,
RETRY_COUNT)
values
(id_val,
lower(v_rt_all_cols(i).event_type),
decode(v_rt_all_cols(i).product_brand,'LTB',2,'HLX',1,'HAL',1,'BOS',3,'VER',4,0),
'Email',
v_rt_all_cols(i).email_id,
'IADAREMINDER',
systimestamp,
systimestamp,
0);
else
vstep_no := '6.02';
vtable_nm := 'after else insertcomm';
insert into parent_tab
(ID ,
CTEM_CODE,
CHA_CODE,
CT_CODE,
CONTACT_POINT_ID,
SOURCE,
RECEIVED_DATE,
SEND_DATE,
RETRY_COUNT)
values
(id_val,
lower(v_rt_all_cols(i).event_type),
decode(v_rt_all_cols(i).product_brand,'LTB',2,'HLX',1,'HAL',1,'BOS',3,'VER',4,0),
'Email',
v_rt_all_cols(i).email_id,
'CORRESPONDENCE',
systimestamp,
systimestamp,
0);
END if;
vstep_no := '6.11';
vtable_nm := 'before chop';
if (v_rt_all_cols(i).ACCOUNT_NUMBER is not null) then
v_rt_all_cols(i).ACCOUNT_NUMBER := 'XXXX'||substr(trim(v_rt_all_cols(i).ACCOUNT_NUMBER),length(trim(v_rt_all_cols(i).ACCOUNT_NUMBER))-3,4);
insert into child_tab
(COM_ID,
KEY,
VALUE)
values
(id_val,
'IB.Correspondence.AccountNumberMasked',
v_rt_all_cols(i).ACCOUNT_NUMBER);
end if;
vstep_no := '6.1';
vtable_nm := 'before stateday';
if (v_rt_all_cols(i).crr_day is not null) then
insert into child_tab
(COM_ID,
KEY,
VALUE)
values
(id_val,
--'IB.Correspondence.Date.Day',
'IB.Crsp.Date.Day',
v_rt_all_cols(i).crr_day);
end if;
vstep_no := '6.2';
vtable_nm := 'before statemth';
if (v_rt_all_cols(i).crr_month is not null) then
insert into child_tab
(COM_ID,
KEY,
VALUE)
values
(id_val,
--'IB.Correspondence.Date.Month',
'IB.Crsp.Date.Month',
v_rt_all_cols(i).crr_month);
end if;
vstep_no := '6.3';
vtable_nm := 'before stateyear';
if (v_rt_all_cols(i).crr_year is not null) then
insert into child_tab
(COM_ID,
KEY,
VALUE)
values
(id_val,
--'IB.Correspondence.Date.Year',
'IB.Crsp.Date.Year',
v_rt_all_cols(i).crr_year);
end if;
vstep_no := '7';
vtable_nm := 'before type';
if (v_rt_all_cols(i).product_type is not null) then
insert into child_tab
(COM_ID,
KEY,
VALUE)
values
(id_val,
'IB.Product.ProductName',
v_rt_all_cols(i).product_type);
end if;
vstep_no := '9';
vtable_nm := 'before title';
if (trim(v_rt_all_cols(i).title) is not null) then
insert into child_tab
(COM_ID,
KEY,
VALUE )
values
(id_val,
'IB.Customer.Title',
trim(v_rt_all_cols(i).title));
end if;
vstep_no := '10';
vtable_nm := 'before surname';
if (v_rt_all_cols(i).surname is not null) then
insert into child_tab
(COM_ID,
KEY,
VALUE)
values
(id_val,
'IB.Customer.LastName',
v_rt_all_cols(i).surname);
end if;
vstep_no := '12';
vtable_nm := 'before postcd';
if (trim(v_rt_all_cols(i).POSTCODE) is not null) then
insert into child_tab
(COM_ID,
KEY,
VALUE)
values
(id_val,
'IB.Customer.Addr.PostCodeMasked',
substr(replace(v_rt_all_cols(i).POSTCODE,' ',''),length(replace(v_rt_all_cols(i).POSTCODE,' ',''))-2,3));
end if;
vstep_no := '13';
vtable_nm := 'before subject';
if (trim(v_rt_all_cols(i).SUBJECT) is not null) then
insert into child_tab
(COM_ID,
KEY,
VALUE)
values
(id_val,
'IB.Correspondence.Subject',
v_rt_all_cols(i).subject);
end if;
vstep_no := '14';
vtable_nm := 'before inactivity';
if (trim(v_rt_all_cols(i).UNREAD_CORRES_PERIOD) is null or
trim(v_rt_all_cols(i).UNREAD_CORRES_PERIOD) = '3' or
trim(v_rt_all_cols(i).UNREAD_CORRES_PERIOD) = '6' or
trim(v_rt_all_cols(i).UNREAD_CORRES_PERIOD) = '9') then
insert into child_tab
(COM_ID,
KEY,
VALUE)
values
(id_val,
'IB.Correspondence.Inactivity',
v_rt_all_cols(i).UNREAD_CORRES_PERIOD);
end if;
vstep_no := '14.1';
vtable_nm := 'after notfound';
end if;
vstep_no := '15';
vtable_nm := 'after notfound';
END LOOP;
end loop;
vstep_no := '16';
vtable_nm := 'before closecur';
CLOSE stg_cursor;
vstep_no := '17';
vtable_nm := 'before commit';
DELETE FROM table_stg;
COMMIT;
vstep_no := '18';
vtable_nm := 'after commit';
EXCEPTION
WHEN OTHERS THEN
ROLLBACK;
success_flag := 1;
vsql_code := SQLCODE;
vsql_errm := SUBSTR(sqlerrm,1,200);
error_logging_pkg.inserterrorlog('samp',vsql_code,vsql_errm, vtable_nm,vstep_no);
RAISE_APPLICATION_ERROR (-20011, 'samp '||vstep_no||' SQLERRM:'||SQLERRM);
end;
ThanksIts bit urgent
NO - it is NOT urgent. Not to us.
If you have an urgent problem you need to hire a consultant.
I have a performance issue in the below code,
Maybe you do and maybe you don't. How are we to really know? You haven't posted ANYTHING indicating that a performance issue exists. Please read the FAQ for how to post a tuning request and the info you need to provide. First and foremost you have to post SOMETHING that actually shows that a performance issue exists. Troubleshooting requires FACTS not just a subjective opinion.
where i am trying to insert the data from table_stg into target_tab and in parent_tab tables and then to child tables via cursor with bulk collect .the target_tab and parent_tab are huge tables and have a row wise trigger enabled on it .the trigger is mandatory . This timetaken for this block to execute is 5000 seconds.Now my requirement is to reduce it to 5 to 10 mins.
Personally I think 5000 seconds (about 1 hr 20 minutes) is very fast for processing 800 trillion rows of data into parent and child tables. Why do you think that is slow?
Your code has several major flaws that need to be corrected before you can even determine what, if anything, needs to be tuned.
This code has the EXIT statement at the beginning of the loop instead of at the end
FETCH stg_cursor BULK COLLECT INTO v_rt_all_cols LIMIT limit_in;
vstep_no := '4';
vtable_nm := 'after fetch';
--EXIT WHEN v_rt_all_cols.COUNT = 0;
EXIT WHEN stg_cursor%NOTFOUND;
The correct place for the %NOTFOUND test when using BULK COLLECT is at the END of the loop; that is, the last statement in the loop.
You can use a COUNT test at the start of the loop but ironically you have commented it out and have now done it wrong. Either move the NOTFOUND test to the end of the loop or remove it and uncomment the COUNT test.
WHEN OTHERS THEN
ROLLBACK;
That basically says you don't even care what problem occurs or whether the problem is for a single record of your 10,000 in the collection. You pretty much just throw away any stack trace and substitute your own message.
Your code also has NO exception handling for any of the individual steps or blocks of code.
The code you posted also begs the question of why you are using NAME=VALUE pairs for child data rows? Why aren't you using a standard relational table for this data?
As others have noted you are using slow-by-slow (row by row processing). Let's assume that PL/SQL, the bulk collect and row-by-row is actually necessary.
Then you should be constructing the parent and child records into collections and then inserting them in BULK using FORALL.
1. Create a collection for the new parent rows
2. Create a collection for the new child rows
3. For each set of LIMIT source row data
a. empty the parent and child collections
b. populate those collections with new parent/child data
c. bulk insert the parent collection into the parent table
d. bulk insert the child collection into the child table
And unless you really want to either load EVERYTHING or abandon everything you should use bulk exception handling so that the clean data gets processed and only the dirty data gets rejected. -
FORALL Exception handling problem
Hi All,
I have one doubt in forall exception handling. I have gone through the SAVE EXCEPTION for bulk collect but i have one more query
BEGIN
FORALL j IN l_tab.first .. l_tab.last
INSERT INTO exception_test
VALUES (l_tab(i));
EXCEPTION
END;
My requirement is when an exception occurs, i ant to print the values of the collection.
e.g. say l_tab (j).emp_number, l_tab (j).emp_id.
How is that possible?
Thanks
Samarth
Edited by: 950810 on Mar 12, 2013 7:28 PM>
I have one doubt in forall exception handling. I have gone through the SAVE EXCEPTION for bulk collect but i have one more query
BEGIN
FORALL j IN l_tab.first .. l_tab.last
INSERT INTO exception_test
VALUES (l_tab(i));
EXCEPTION
END;
My requirement is when an exception occurs, i ant to print the values of the collection.
e.g. say l_tab (j).emp_number, l_tab (j).emp_id.
How is that possible?
>
Post the code you are using. You didn't post the FORALL that is using SAVE EXCEPTIONS.
The SQL%BULK_EXCEPTIONS associative array that you get has the INDEX of the collection element that caused the exception.
So you need to use those indexes to index into the original collection to get whatever values are in it.
One index from the exception array is:
SQL%BULK_EXCEPTIONS(i).error_index So if your original collection is named 'myCollection' you would reference that collection value as:
myCollection(SQL%BULK_EXCEPTIONS(i).error_index); See 'Handling FORALL Exceptions (%BULK_EXCEPTIONS Attribute)' in the PL/SQL Language doc
http://docs.oracle.com/cd/B28359_01/appdev.111/b28370/tuning.htm#i49099
>
All exceptions raised during the execution are saved in the cursor attribute %BULK_EXCEPTIONS, which stores a collection of records. Each record has two fields:
%BULK_EXCEPTIONS(i).ERROR_INDEX holds the iteration of the FORALL statement during which the exception was raised.
%BULK_EXCEPTIONS(i).ERROR_CODE holds the corresponding Oracle Database error code.
The values stored by %BULK_EXCEPTIONS always refer to the most recently executed FORALL statement. The number of exceptions is saved in %BULK_EXCEPTIONS.COUNT. Its subscripts range from 1 to COUNT.
The individual error messages, or any substitution arguments, are not saved, but the error message text can looked up using ERROR_CODE with SQLERRM as shown in Example 12-9.
You might need to work backward to determine which collection element was used in the iteration that caused an exception. For example, if you use the INDICES OF clause to process a sparse collection, you must step through the elements one by one to find the one corresponding to %BULK_EXCEPTIONS(i).ERROR_INDEX. If you use the VALUES OF clause to process a subset of elements, you must find the element in the index collection whose subscript matches %BULK_EXCEPTIONS(i).ERROR_INDEX, and then use that element's value as the subscript to find the erroneous element in the original collection. -
Cursor with bulk collect ...
Hi experts,
CURSOR ZIP_CUR IS SELECT * FROM ZIP_MASTER WHERE ..(SUBQUERY)
OPEN ZIP_CUR;
LOOP
EXIT WHEN C1%NOTFOUND;
FETCH ZIP_CUR BULK COLLECT INTO ZIP_REC LIMIT 1000;
FOR I IN ZIP_REC.FIRST..ZIP_REC.LAST
LOOP
END LOOP
END LOOP
If there is no data in cusor then the looping after bulk collect is throughing VALUE_ERROR
but why EXIT WHEN C1%NOTFOUND not terminating procedure??
now i am using the same select statement in cursor to find the data and raise user defined exception..
is there any other way to handle in execption??
Many thanks,
Kalinga..You can try something like this -
satyaki>
satyaki>declare
2 CURSOR c_emp
3 IS
4 SELECT *
5 FROM emp_s
6 WHERE deptno in (
7 SELECT deptno
8 from emp_s
9 where job = 'ANALYST'
10 );
11
12 type emp_tt is table of emp_s%rowtype index by pls_integer;
13
14 emp_rec emp_tt;
15 begin
16
17 OPEN c_emp;
18 LOOP
19 EXIT WHEN c_emp%NOTFOUND;
20 FETCH c_emp BULK COLLECT INTO emp_rec LIMIT 1000;
21 FOR I IN 1..emp_rec.COUNT
22 LOOP
23 dbms_output.put_line('Empno: '||emp_rec(I).empno);
24 dbms_output.put_line('Ename: '||emp_rec(I).ename);
25 dbms_output.put_line('Mgr: '||emp_rec(I).mgr);
26 END LOOP;
27 END LOOP;
28 exception
29 when others then
30 dbms_output.put_line(sqlerrm);
31 end;
32 /
Empno: 7902
Ename: FORD
Mgr: 7566
Empno: 7839
Ename: KING
Mgr: 7839
Empno: 7788
Ename: SCOTT
Mgr: 7566
Empno: 7698
Ename: BLAKE
Mgr: 7839
PL/SQL procedure successfully completed.
satyaki>Regards.
Satyaki De. -
Loading data into multiple tables - Bulk collect or regular Fetch
I have a procedure to load data from one source table into eight different destination tables. The 8 tables have some of the columns of the source table with a common key.
I have run into a couple of problems and have a few questions where I would like to seek advice:
1.) Procedure with and without the BULK COLLECT clause took the same time for 100,000 records. I thought I would see improvement in performance when I include BULK COLLECT with LIMIT.
2.) Updating the Load_Flag in source_table happens only for few records and not all. I had expected all records to be updated
3.) Are there other suggestions to improve the performance? or could you provide links to other posts or articles on the web that will help me improve the code?
Notes:
1.) 8 Destination tables have at least 2 Million records each, have multiple indexes and are accessed by application in Production
2.) There is an initial load of 1 Million rows with a subsequent daily load of 10,000 rows. Daily load will have updates for existing rows (not shown in code structure below)
The structure of the procedure is as follows
Declare
dest_type is table of source_table%ROWTYPE;
dest_tab dest_type ;
iCount NUMBER;
cursor source_cur is select * from source_table FOR UPDATE OF load_flag;
BEGIN
OPEN source_cur;
LOOP
FETCH source_cur -- BULK COLLECT
INTO dest_tab -- LIMIT 1000
EXIT WHEN source_cur%NOTFOUND;
FOR i in dest_tab.FIRST .. dest_tab.LAST LOOP
<Insert into app_tab1 values key, col12, col23, col34 ;>
<Insert into app_tab2 values key, col15, col29, col31 ;>
<Insert into app_tab3 values key, col52, col93, col56 ;>
UPDATE source_table SET load_flag = 'Y' WHERE CURRENT OF source_cur ;
iCount := iCount + 1 ;
IF iCount = 1000 THEN
COMMIT ;
iCount := 0 ;
END IF;
END LOOP;
END LOOP ;
COMMIT ;
END ;
Edited by: user11368240 on Jul 14, 2009 11:08 AMAssuming you are on 10g or later, the PL/SQL compiler generates the bulk fetch for you automatically, so your code is the same as (untested):
DECLARE
iCount NUMBER;
CURSOR source_cur is select * from source_table FOR UPDATE OF load_flag;
BEGIN
OPEN source_cur;
FOR r IN source_cur
LOOP
<Insert into app_tab1 values key, col12, col23, col34 ;>
<Insert into app_tab2 values key, col15, col29, col31 ;>
<Insert into app_tab3 values key, col52, col93, col56 ;>
UPDATE source_table SET load_flag = 'Y' WHERE CURRENT OF source_cur ;
iCount := iCount + 1 ;
IF iCount = 1000 THEN
COMMIT ;
iCount := 0 ;
END IF;
END LOOP;
COMMIT ;
END ;However most of the benefit of bulk fetching would come from using the array with a FORALL expression, which the PL/SQL compiler can't automate for you.
If you are fetching 1000 rows at a time, purely from a code simplification point of view you could lose iCount and the IF...COMMIT...END IF and just commit each time after looping through the 1000-row array.
However I'm not sure how committing every 1000 rows helps restartability, even if your real code has a WHERE clause in the cursor so that it only selects rows with load_flag = 'N' or whatever. If you are worried that it will roll back all your hard work on failure, why not just commit in your exception handler? -
Retruning bulk collect into---Error
the code:
DECLARE
v_file UTL_FILE.file_type;
TYPE emp_tab_type IS TABLE OF emp%ROWTYPE;
v_row VARCHAR2 (100);
emp_tab emp_tab_type;
BEGIN
v_file := UTL_FILE.fopen ('XML_DIR', 'emp.txt', 'w');
EXECUTE IMMEDIATE 'select * from emp'
RETURNING BULK COLLECT INTO emp_tab;
FOR i IN emp_tab.FIRST .. emp_tab.LAST
LOOP
v_row :=
emp_tab.empno
|| ','
|| emp_tab.ename
|| ','
|| emp_tab.job
|| ','
|| emp_tab.mgr
|| ','
|| emp_tab.hiredate
|| ','
|| emp_tab.sal
|| ','
|| emp_tab.comm
|| ','
|| emp_tab.deptno;
UTL_FILE.put_line (v_file, v_row, TRUE);
END LOOP;
UTL_FILE.fclose (v_file);
EXCEPTION
WHEN OTHERS
THEN
UTL_FILE.fclose (v_file);
END;
the error:
ORA-06550: line 12, column 7:
PLS-00429: unsupported feature with RETURNING clause
please help!Couple of errors:
1) There is absolutely no need to use dynamic SQL here, so get rid of the EXECUTE IMMEDIATE.
2) If any error occurs, then you are hiding it from the caller by your WHEN OTHERS THEN exception handler. Just get rid of it, or use WHEN OTHERS THEN UTL_FILE.fclose (v_file); RAISE; END;
3) You have to refer to the elements of your nested table emp_tab and not to the nested table itself, so add a "(i)" to refer to the element inside the loop.
Example:
SQL> DECLARE
2 TYPE emp_tab_type IS TABLE OF emp%ROWTYPE;
3 v_row VARCHAR2 (100);
4 emp_tab emp_tab_type;
5 BEGIN
6 select *
7 BULK COLLECT INTO emp_tab
8 from emp
9 ;
10 FOR i IN emp_tab.FIRST .. emp_tab.LAST
11 LOOP
12 v_row :=
13 emp_tab(i).empno || ',' ||
14 emp_tab(i).ename || ',' ||
15 emp_tab(i).job || ',' ||
16 emp_tab(i).mgr || ',' ||
17 emp_tab(i).hiredate || ',' ||
18 emp_tab(i).sal || ',' ||
19 emp_tab(i).comm || ',' ||
20 emp_tab(i).deptno
21 ;
22 dbms_output.put_line(v_row);
23 END LOOP;
24 END;
25 /
7369,SMITH,CLERK,7902,17-12-1980 00:00:00,800,,20
7499,ALLEN,SALESMAN,7698,20-02-1981 00:00:00,1600,300,30
7521,WARD,SALESMAN,7698,22-02-1981 00:00:00,1250,500,30
7566,JONES,MANAGER,7839,02-04-1981 00:00:00,2975,,20
7654,MARTIN,SALESMAN,7698,28-09-1981 00:00:00,1250,1400,30
7698,BLAKE,MANAGER,7839,01-05-1981 00:00:00,2850,,30
7782,CLARK,MANAGER,7839,09-06-1981 00:00:00,2450,,10
7788,SCOTT,ANALYST,7566,09-12-1982 00:00:00,3000,,20
7839,KING,PRESIDENT,,17-11-1981 00:00:00,5000,,10
7844,TURNER,SALESMAN,7698,08-09-1981 00:00:00,1500,0,30
7876,ADAMS,CLERK,7788,12-01-1983 00:00:00,1100,,20
7900,JAMES,CLERK,7698,03-12-1981 00:00:00,950,,30
7902,FORD,ANALYST,7566,03-12-1981 00:00:00,3000,,20
7934,MILLER,CLERK,7782,23-01-1982 00:00:00,1300,,10
PL/SQL procedure successfully completed.Regards,
Rob. -
Exception Handling for inserts
Hi,
My requirement is to populate a table with values got by selecting columns from various table on join conditions. It works fine if all the rows inserted are unique. However if the row to be inserted is duplicate, it violates the uniqueness constraint.
I want an exception wherein if select query returns 100 rows, of which 80 are already there in the table to be populated, it should just insert the 20 records.
Below is the SP i wrote for the same. However, as soon as it meets exception condition, it just prints the condition and exits, without processing the rest of the records. Please look at the SP below and suggest a solution.
create or replace
PROCEDURE PP_CMC_TEST AS
cursor c1 is
(select cdu.subscription_id,max(cdu.account_id),max(s.subscription_versn_start_date),
max(s.service_plan_id),max(sbp.billing_period_id),sysdate-1
,cdu.device_name, cdu.resource_id,sum(cdu.usage),max(cdu.unit_of_measurement)
from
subscriptions s, subscription_billing_period sbp, consolidated_daily_usage cdu
where s.version_end_date is null and
sysdate-1 between sbp.start_date and sbp.end_date and
cdu.usage_date between sbp.start_date and sbp.end_date
and s.subscription_id = cdu.subscription_id
and sbp.subscription_id = cdu.subscription_id
and sbp.subscription_id = s.subscription_id
and s.subscription_versn_start_date=sbp.subscription_versn_start_date
group by cdu.subscription_id,cdu.device_name, cdu.resource_id);
a number;
b number;
c date;
d number;
e number;
f date;
g varchar2 (255);
h number;
i number;
j varchar2(60);
BEGIN
OPEN c1;
LOOP
FETCH c1 INTO a,b,c,d,e,f,g,h,i,j;
EXIT WHEN c1%NOTFOUND;
insert into cmc_test
(subscription_id,account_id,subscription_versn_start_date,service_plan_id,billing_period_id,curr_date,
device_name,resource_id,usage,unit_of_measurement) values
(a,b,c,d,e,f,g,h,i,j);
END LOOP;
EXCEPTION
WHEN DUP_VAL_ON_INDEX
THEN
DBMS_OUTPUT.PUT_LINE('DUPLICATE RECORD FOUND');
commit;
CLOSE c1;
END PP_CMC_TEST;Edited by: BluShadow on 07-Feb-2012 09:03
added {noformat}{noformat} tags (for what it was worth). Please read {message:id=9360002} and learn to do this yourself in future.Using SQL you would create an error table and modify the INSERT to log the errors. See the 'Inserting Into a Table with Error Logging' section of http://docs.oracle.com/cd/B19306_01/server.102/b14200/statements_9014.htm. Note this approach will not work if you are using direct path loads since the log table won't be used.
If you are going to use PL/SQL for this then what you want is to use BULK COLLECT and then a FORALL with a SAVE EXCEPTIONS clause.
>
A. BULK COLLECT INTO plsqlTable LIMIT 5000 - These are your new records you want to INSERT
B. FORALL ... SAVE EXCEPTIONS - This is the INSERT query to insert the new records
C. Use a bulk exception handler. Any record in the FORALL that causes an exception will have it's index put into the bulk exception array. In the bulk exception handler you can loop through the array and access the records that caused the error using the index into the plsqlTable and do any error logging you need to do.
>
The bulk exception array will have the plsql table index of the row that caused the error. You can index into the plsql table (see Step A above) to access the record and then log it, INSERT it into a duplicates table or whatever you want.
The important thing is that the records that do not have errors will still get processed. Similar result to what will happen if you use SQL and an error table. -
Hi All,
I've one doubt regarding the bulk operations using the forall statement.
Check below eample:
CREATE TABLE emp_temp AS SELECT * FROM employees;
DECLARE
TYPE empid_tab IS TABLE OF employees.employee_id%TYPE;
emp_sr empid_tab;
-- create an exception handler for ORA-24381
errors NUMBER;
dml_errors EXCEPTION;
PRAGMA EXCEPTION_INIT(dml_errors, -24381);
BEGIN
SELECT employee_id BULK COLLECT INTO emp_sr FROM emp_temp
WHERE hire_date < '30-DEC-94';
-- add '_SR' to the job_id of the most senior employees
FORALL i IN emp_sr.FIRST..emp_sr.LAST SAVE EXCEPTIONS
UPDATE emp_temp SET job_id = job_id || '_SR'
WHERE emp_sr(i) = emp_temp.employee_id;
-- If any errors occurred during the FORALL SAVE EXCEPTIONS,
-- a single exception is raised when the statement completes.
EXCEPTION
WHEN dml_errors THEN -- Now we figure out what failed and why.
errors := SQL%BULK_EXCEPTIONS.COUNT;
DBMS_OUTPUT.PUT_LINE('Number of statements that failed: ' || errors);
FOR i IN 1..errors LOOP
DBMS_OUTPUT.PUT_LINE('Error #' || i || ' occurred during '||
'iteration #' || SQL%BULK_EXCEPTIONS(i).ERROR_INDEX);
DBMS_OUTPUT.PUT_LINE('Error message is ' ||
SQLERRM(-SQL%BULK_EXCEPTIONS(i).ERROR_CODE));
END LOOP;
END;
Here we update using bulk collect & the exceptions for each iterations are kept separately.
In case, I want to know whether the sql statements in each array are executed separately or all the statements are executed in bulk?
Thanks
DeepakMay this will answer it...
FORALL - documentation
Maybe you are looking for
-
I need help. I caught my spose cheating on me and I need to find out what the 800 plus text read that they were sending back and forth. I have an external hard drive that the itunes is backed up to. I understand that itunes backsup these text when th
-
Uninstall previous versions when installing new ones?
I upgrade my Photoshop Elements to Photoshop CS5 that comes with Bridge CS5 also, by downloading and installing the files. Do I have to uninstall the Photoshop Elements and Bridge CS4 to only have the upgraded versions?
-
How to Call SAP ECC transactions into CRM IC Webclient Profile Screen
Dear all, We are implementing IC Webclient application for our Clientu2019s call center operations. All sales related activities are being created in back end SAP ECC system like, starting from Quotation to Sales Order, Deliveries and Billing. Client
-
HT4847 How do I get my pics off iCloud & on to my new phone?
How do I get my pics off iCloud & on to my new phone?
-
Process Multiple Images gives Error.
When trying to process multiple pictures in the editor (saving them to a new folder for including them in my blog) it processes one picture and then gives me an error message box with "Could not complete your request because of a program error". I th