Oracle ORA-00001:插入0行时违反了唯一约束

Oracle ORA-00001:插入0行时违反了唯一约束,oracle,sql-insert,oracle12c,unique-constraint,dml,Oracle,Sql Insert,Oracle12c,Unique Constraint,Dml,我正在尝试将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));

我正在尝试将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;
/
更新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:表A正在变化,触发器/函数可能看不到它
,但代码捕获所有异常并返回null

显然,从发生变异的表中进行选择是非零的,必须固定


我很生气,因为我数不清有多少次,当其他人返回null时,我告诉同事们停止使用
异常。这又是一个例子,它完全掩盖了问题,我花了一整天的时间来解释它。

Select返回了0行,没问题

然而,当向表中插入行时,我们实际上是通过一个函数查询同一个表。返回的函数
ORA-04091:表A正在变异,触发器/函数可能看不到它
,但它被捕获在异常块中,并返回了
null
。这导致查询返回行


当其他人返回null时,切勿使用异常
<代码>拒绝限制0
意味着不允许出现错误,因此显然它将在第一个错误时停止。您是否正在寻找
拒绝无限限制
?不,我希望没有错误。我使用日志错误只是为了查看表中的内容。我的问题是表中应该没有插入任何内容,查询返回0行…请检查
select count(*)
。由于索引损坏而导致错误的
计数(*)
并不少见。您还应该意识到,如果不显示视图的一些细节,就无法获得有意义的完整响应。例如,我怀疑如果你
选择*
你会看到一些数据。@MarmiteBomber感谢你指出
计数(*)
可能会给出与选择所有值不同的结果。但是,即使我使用完全相同的查询将所有数据插入到不同的表中,我也可以看到有0行(请参见我更新的问题)。。。如果我从testx\u视图中选择了*,我会看到0条记录…请显示约束。
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;
/
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
/