ORA-00001: 插入 0 行时违反了唯一约束
ORA-00001: unique constraint violated when inserting 0 rows
我正在尝试将 0 行插入到具有唯一约束的 table 中,但我收到 ORA-00001:违反了唯一约束...
下面是 PL/SQL 块,我希望能很好地解决问题
declare
l_cnt number;
begin
set transaction isolation level serializable;
select count(*) into l_cnt from test_view;
dbms_output.put_line('count = ' || to_char(l_cnt));
insert into <table>(<columns>)
select <columns> from test_view
log errors ('run1')
reject limit 0
;
dbms_output.put_line('success');
exception
when others then
dbms_output.put_line('ERRROR!');
dbms_output.put_line(sqlerrm);
rollback;
end;
/
这是输出
count = 0
ERRROR!
ORA-00001: unique constraint (<SCHEMA>.<CONSTRAINT>) violated
果然ERR$_<table>
table...
中有记录
如果我在插入语句中添加 where 1 = 0
,一切正常,没有插入任何内容。
我仍然不相信我所看到的:)
Oracle Database 12c Standard Edition Release 12.2.0.1.0 - 64bit Production
更新 1
下面的示例未在视图上使用 count(*)
,因为这可能会导致不同的查询计划,即为插入选择所有必需的值。
declare
l_cnt number;
begin
set transaction isolation level serializable;
insert into testx_table
select * from testx_view d;
select count(*) into l_cnt from testx_table;
dbms_output.put_line('count = ' || to_char(l_cnt));
insert into <table>(<columns>)
select * from testx_view d
log errors ('run2')
reject limit 0;
dbms_output.put_line('success');
exception
when others then
dbms_output.put_line('ERRROR!');
dbms_output.put_line(sqlerrm);
rollback;
end;
/
更新 2
我能够重现该行为。
CREATE TABLE A(ID NUMBER PRIMARY KEY)
/
CREATE FUNCTION F(ID_ NUMBER) RETURN NUMBER
AS
L_ID NUMBER;
BEGIN
SELECT ID INTO L_ID FROM A WHERE ID = ID_;
RETURN L_ID;
EXCEPTION
WHEN OTHERS THEN
RETURN NULL;
END;
/
BEGIN
DBMS_ERRLOG.CREATE_ERROR_LOG('A');
END;
/
BEGIN
INSERT INTO A VALUES (1);
INSERT INTO A SELECT 1 FROM DUAL WHERE F(1) IS NULL
LOG ERRORS INTO ERR$_A;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(SQLERRM);
END;
/
SELECT * FROM ERR$_A
/
这一切都归结为查询正在从函数内部修改的 table。函数抛出 ORA-04091: table A is mutating, trigger/function may not see it
但代码捕获所有异常和 returns null.
显然,从 table 中选择正在发生变化的是一个错误,必须加以修复。
而且我很生气,因为我数不清告诉我的同事停止使用 exception when others then return null
的次数。这又是一个完全掩盖问题的例子,我花了一整天时间调试它。
Select return编辑了 0 行,没问题。
然而,当向 table 插入行时,我们实际上是通过函数查询相同的 table。函数 returned ORA-04091: table A is mutating, trigger/function may not see it
但它在异常块中被捕获并且 null
被 returned。这导致查询 return 行...
切勿使用 exception when others then return null
!!!
我正在尝试将 0 行插入到具有唯一约束的 table 中,但我收到 ORA-00001:违反了唯一约束...
下面是 PL/SQL 块,我希望能很好地解决问题
declare
l_cnt number;
begin
set transaction isolation level serializable;
select count(*) into l_cnt from test_view;
dbms_output.put_line('count = ' || to_char(l_cnt));
insert into <table>(<columns>)
select <columns> from test_view
log errors ('run1')
reject limit 0
;
dbms_output.put_line('success');
exception
when others then
dbms_output.put_line('ERRROR!');
dbms_output.put_line(sqlerrm);
rollback;
end;
/
这是输出
count = 0
ERRROR!
ORA-00001: unique constraint (<SCHEMA>.<CONSTRAINT>) violated
果然ERR$_<table>
table...
如果我在插入语句中添加 where 1 = 0
,一切正常,没有插入任何内容。
我仍然不相信我所看到的:)
Oracle Database 12c Standard Edition Release 12.2.0.1.0 - 64bit Production
更新 1
下面的示例未在视图上使用 count(*)
,因为这可能会导致不同的查询计划,即为插入选择所有必需的值。
declare
l_cnt number;
begin
set transaction isolation level serializable;
insert into testx_table
select * from testx_view d;
select count(*) into l_cnt from testx_table;
dbms_output.put_line('count = ' || to_char(l_cnt));
insert into <table>(<columns>)
select * from testx_view d
log errors ('run2')
reject limit 0;
dbms_output.put_line('success');
exception
when others then
dbms_output.put_line('ERRROR!');
dbms_output.put_line(sqlerrm);
rollback;
end;
/
更新 2
我能够重现该行为。
CREATE TABLE A(ID NUMBER PRIMARY KEY)
/
CREATE FUNCTION F(ID_ NUMBER) RETURN NUMBER
AS
L_ID NUMBER;
BEGIN
SELECT ID INTO L_ID FROM A WHERE ID = ID_;
RETURN L_ID;
EXCEPTION
WHEN OTHERS THEN
RETURN NULL;
END;
/
BEGIN
DBMS_ERRLOG.CREATE_ERROR_LOG('A');
END;
/
BEGIN
INSERT INTO A VALUES (1);
INSERT INTO A SELECT 1 FROM DUAL WHERE F(1) IS NULL
LOG ERRORS INTO ERR$_A;
EXCEPTION
WHEN OTHERS THEN
DBMS_OUTPUT.PUT_LINE(SQLERRM);
END;
/
SELECT * FROM ERR$_A
/
这一切都归结为查询正在从函数内部修改的 table。函数抛出 ORA-04091: table A is mutating, trigger/function may not see it
但代码捕获所有异常和 returns null.
显然,从 table 中选择正在发生变化的是一个错误,必须加以修复。
而且我很生气,因为我数不清告诉我的同事停止使用 exception when others then return null
的次数。这又是一个完全掩盖问题的例子,我花了一整天时间调试它。
Select return编辑了 0 行,没问题。
然而,当向 table 插入行时,我们实际上是通过函数查询相同的 table。函数 returned ORA-04091: table A is mutating, trigger/function may not see it
但它在异常块中被捕获并且 null
被 returned。这导致查询 return 行...