FOR i IN 1 .. SQL%BULK_EXCEPTIONS.COUNT 如何指向引发异常的集合元素?
How does FOR i IN 1 .. SQL%BULK_EXCEPTIONS.COUNT point to the elements of the collection that threw the exceptions?
我已将此代码作为 :
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 * 999999999999
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;
/
谁能解释一下 V_EMP_ID(i)
如何指向导致异常的实际元素,因为 i
在 1 .. SQL%BULK_EXCEPTIONS.COUNT
中。 V_EMP_ID(i)
不应该在第一次迭代中始终指向集合的第一个元素吗?
PS 于 12 月 17 日添加了以下内容
在我下面的代码中,出于某种原因,我试图在不使用 MERGE INTO
的情况下模拟 MERGE INTO
功能。
使用集合,我将记录从临时 table 插入到主 table。如果该行存在于主 table 中,我们将得到 DUP_VAL_ON_INDEX
类错误,并使用 SAVE EXCEPTIONS
.
保存错误详细信息
在 EXCEPTION
块中,我想更新所有出错的主要 table 行,并使用临时 table.
中的一组值更新它们
令人惊讶的是,FORALL i IN 1 .. SQL%BULK_EXCEPTIONS.COUNT
和 temp_data(i)
为我更新了主要 table 中的正确行。我也尝试了非连续行并且效果很好。这怎么可能?
declare
TYPE data_tbl IS TABLE OF EMPLOYEE_TEMP%rowtype INDEX BY PLS_INTEGER;
temp_data data_tbl;
begin
select * bulk collect into temp_data from EMPLOYEE_TEMP
where EVENT_OID='30047767_1' and USERID='SINISDI2';
FORALL i IN 1 .. temp_data.COUNT SAVE EXCEPTIONS
INSERT INTO EMPLOYEE D
(D.VPD_KEY,
D.OID,
D.EVENT_OID,
D.PID,
D.AMOUNT,
D.MIR,
D.REPORTING,
D.MODIFIED_BY_USER,
D.MODIFIED_ON,
D.VERSION,
D.TYPE_OID,
D.F_ELIGIBLE)
VALUES ( temp_data(i).VPD_KEY,
temp_data(i).OID,
temp_data(i).EVENT_OID,
temp_data(i).PID,
temp_data(i).AMOUNT,
temp_data(i).MIR,
temp_data(i).REPORTING,
temp_data(i).USERID,
SYSDATE,
0,
temp_data(i).TYPE_OID,
temp_data(i).F_ELIGIBLE
);
EXCEPTION
WHEN OTHERS
THEN
IF SQLCODE = -24381
THEN
FORALL i IN 1 .. SQL%BULK_EXCEPTIONS.COUNT
UPDATE EMPLOYEE D
SET D.AMOUNT=temp_data(i).AMOUNT,
D.REPORTING=temp_data(i).REPORTING,
D.MIR=temp_data(i).MIR,
D.MODIFIED_BY_USER=temp_data(i).USERID,
D.MODIFIED_ON = temp_data(i).MODIFIED_ON,
D.VERSION = D.VERSION+1,
D.F_ELIGIBLE = S.F_ELIGIBLE
where D.PID = temp_data(i).PID AND D.TYPE_OID = temp_data(i).TYPE_OID;
ELSE
DBMS_OUTPUT.PUT_LINE(SQLERRM(SQLCODE)) ;
END IF;
end;
/
引自首都12.4.1.4 Handling FORALL Exceptions After FORALL Statement Completes:
SQL%BULK_EXCEPTIONS(i).ERROR_INDEX is the number of the DML statement that failed.
DML语句的编号相当于集合中的元素索引
看看下面的工作示例:
create table tab (id, val check (val<=3)) as
select rownum, rownum from dual connect by level<=3
/
declare
type idtab is table of int;
ids idtab;
begin
select id bulk collect into ids
from tab;
declare
forallexcp exception;
pragma exception_init (forallexcp, -24381);
begin
forall i in 1..ids.count save exceptions
update tab set val = val + 1
where id = ids(i);
exception when forallexcp then
dbms_output.put_line (
sql%rowcount||' row(s) inserted ('||sql%bulk_exceptions.count||' with error).');
for i in 1..sql%bulk_exceptions.count loop dbms_output.put_line (
'id='||ids(sql%bulk_exceptions(i).error_index)||' sqlerrm='||
sqlerrm (-(sql%bulk_exceptions(i).error_code)));
end loop;
end;
end;
/
结果:
2 row(s) inserted (1 with error).
id=3 sqlerrm=ORA-02290: check constraint (.) violated
我已将此代码作为
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 * 999999999999
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;
/
谁能解释一下 V_EMP_ID(i)
如何指向导致异常的实际元素,因为 i
在 1 .. SQL%BULK_EXCEPTIONS.COUNT
中。 V_EMP_ID(i)
不应该在第一次迭代中始终指向集合的第一个元素吗?
PS 于 12 月 17 日添加了以下内容
在我下面的代码中,出于某种原因,我试图在不使用 MERGE INTO
的情况下模拟 MERGE INTO
功能。
使用集合,我将记录从临时 table 插入到主 table。如果该行存在于主 table 中,我们将得到 DUP_VAL_ON_INDEX
类错误,并使用 SAVE EXCEPTIONS
.
保存错误详细信息
在 EXCEPTION
块中,我想更新所有出错的主要 table 行,并使用临时 table.
中的一组值更新它们
令人惊讶的是,FORALL i IN 1 .. SQL%BULK_EXCEPTIONS.COUNT
和 temp_data(i)
为我更新了主要 table 中的正确行。我也尝试了非连续行并且效果很好。这怎么可能?
declare
TYPE data_tbl IS TABLE OF EMPLOYEE_TEMP%rowtype INDEX BY PLS_INTEGER;
temp_data data_tbl;
begin
select * bulk collect into temp_data from EMPLOYEE_TEMP
where EVENT_OID='30047767_1' and USERID='SINISDI2';
FORALL i IN 1 .. temp_data.COUNT SAVE EXCEPTIONS
INSERT INTO EMPLOYEE D
(D.VPD_KEY,
D.OID,
D.EVENT_OID,
D.PID,
D.AMOUNT,
D.MIR,
D.REPORTING,
D.MODIFIED_BY_USER,
D.MODIFIED_ON,
D.VERSION,
D.TYPE_OID,
D.F_ELIGIBLE)
VALUES ( temp_data(i).VPD_KEY,
temp_data(i).OID,
temp_data(i).EVENT_OID,
temp_data(i).PID,
temp_data(i).AMOUNT,
temp_data(i).MIR,
temp_data(i).REPORTING,
temp_data(i).USERID,
SYSDATE,
0,
temp_data(i).TYPE_OID,
temp_data(i).F_ELIGIBLE
);
EXCEPTION
WHEN OTHERS
THEN
IF SQLCODE = -24381
THEN
FORALL i IN 1 .. SQL%BULK_EXCEPTIONS.COUNT
UPDATE EMPLOYEE D
SET D.AMOUNT=temp_data(i).AMOUNT,
D.REPORTING=temp_data(i).REPORTING,
D.MIR=temp_data(i).MIR,
D.MODIFIED_BY_USER=temp_data(i).USERID,
D.MODIFIED_ON = temp_data(i).MODIFIED_ON,
D.VERSION = D.VERSION+1,
D.F_ELIGIBLE = S.F_ELIGIBLE
where D.PID = temp_data(i).PID AND D.TYPE_OID = temp_data(i).TYPE_OID;
ELSE
DBMS_OUTPUT.PUT_LINE(SQLERRM(SQLCODE)) ;
END IF;
end;
/
引自首都12.4.1.4 Handling FORALL Exceptions After FORALL Statement Completes:
SQL%BULK_EXCEPTIONS(i).ERROR_INDEX is the number of the DML statement that failed.
DML语句的编号相当于集合中的元素索引
看看下面的工作示例:
create table tab (id, val check (val<=3)) as
select rownum, rownum from dual connect by level<=3
/
declare
type idtab is table of int;
ids idtab;
begin
select id bulk collect into ids
from tab;
declare
forallexcp exception;
pragma exception_init (forallexcp, -24381);
begin
forall i in 1..ids.count save exceptions
update tab set val = val + 1
where id = ids(i);
exception when forallexcp then
dbms_output.put_line (
sql%rowcount||' row(s) inserted ('||sql%bulk_exceptions.count||' with error).');
for i in 1..sql%bulk_exceptions.count loop dbms_output.put_line (
'id='||ids(sql%bulk_exceptions(i).error_index)||' sqlerrm='||
sqlerrm (-(sql%bulk_exceptions(i).error_code)));
end loop;
end;
end;
/
结果:
2 row(s) inserted (1 with error).
id=3 sqlerrm=ORA-02290: check constraint (.) violated