【问题标题】:ORA-00001: unique constraint violated when inserting 0 rowsORA-00001: 插入 0 行时违反唯一约束
【发布时间】: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$_&lt;table&gt; 表中有一条记录……

如果我在插入语句中添加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
/

sqlfiddle

这一切都归结为从函数内部查询正在修改的表。函数会抛出 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 planselect count(*)。由于 index 损坏而得到错误的count(*) 并不少见。您还应该意识到,如果不显示视图的一些细节,您将无法获得有意义的响应。例如。我怀疑如果你 select * 你会看到一些数据。
  • @MarmiteBomber 感谢您指出count(*) 可能会给出选择所有值的不同结果。但是,即使我使用完全相同的查询将所有数据插入到不同的表中,我也可以看到有 0 行(请参阅我更新的问题)...如果我这样做 select * from testx_view 我会看到 0 条记录...跨度>
  • 请显示约束。

标签: oracle sql-insert oracle12c unique-constraint dml


【解决方案1】:

Select 返回 0 行,没关系。

但是,在向表中插入行时,我们实际上是通过函数查询同一个表。该函数返回ORA-04091: table A is mutating, trigger/function may not see it,但它在异常块中被捕获并返回null。这导致查询返回行...

永远不要使用exception when others then return null!!!

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 2014-11-06
    • 1970-01-01
    • 1970-01-01
    • 2016-04-08
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多