【发布时间】:2021-06-28 09:49:38
【问题描述】:
我正在尝试将 0 行插入到具有唯一约束的表中,但我得到 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> 表中有一条记录……
如果我在插入语句中添加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
/
这一切都归结为从函数内部查询正在修改的表。函数会抛出 ORA-04091: table A is mutating, trigger/function may not see it,但代码会捕获所有异常并返回 null。
显然,从发生变异的表中进行选择是一个 nono,必须修复。
我很生气,因为我数不清有多少次我告诉我的同事停止使用exception when others then return null。这又是一个完全掩盖问题的例子,我花了一整天的时间调试它。
【问题讨论】:
-
reject limit 0表示不允许出现任何错误,所以显然它会在第一个错误处停止。你在找reject limit unlimited吗? -
不,我希望没有错误。我使用日志错误只是为了查看表中的内容。我的问题是应该没有插入表中,查询返回 0 行...
-
检查execution plan 的
select count(*)。由于 index 损坏而得到错误的count(*)并不少见。您还应该意识到,如果不显示视图的一些细节,您将无法获得有意义的响应。例如。我怀疑如果你select *你会看到一些数据。 -
@MarmiteBomber 感谢您指出
count(*)可能会给出选择所有值的不同结果。但是,即使我使用完全相同的查询将所有数据插入到不同的表中,我也可以看到有 0 行(请参阅我更新的问题)...如果我这样做select * from testx_view我会看到 0 条记录...跨度> -
请显示约束。
标签: oracle sql-insert oracle12c unique-constraint dml