【问题标题】:How to skip unique constraint error如何跳过唯一约束错误
【发布时间】:2015-11-27 05:26:49
【问题描述】:

我正在尝试将值插入到 sql 表中,但在 sql 查询中出现此错误

SQL Error: ORA-00001: unique constraint (uniqueKey) violated
00001. 00000 -  "unique constraint (%s.%s) violated"
*Cause:    An UPDATE or INSERT statement attempted to insert a duplicate key.
       For Trusted Oracle configured in DBMS MAC mode, you may see
       this message if a duplicate entry exists at a different level.
*Action:   Either remove the unique restriction or do not insert the key.

有没有办法跳过这个错误并继续插入。像这样的

try
   insert query
catch (unique constraint error)
   continue inserting other values

【问题讨论】:

标签: sql oracle


【解决方案1】:

存在提示ignore_row_on_dupkey_index(<table name>, <unique index name>)

HUSQVIK@hq_pdb_tcp> CREATE TABLE tmp (val NUMBER CONSTRAINT pk_tmp PRIMARY KEY);

Table created.

HUSQVIK@hq_pdb_tcp> INSERT /*+ ignore_row_on_dupkey_index(tmp, pk_tmp) */ INTO tmp (val) SELECT 1 FROM DUAL CONNECT BY LEVEL <= 3;

1 row created.

看到我插入了三个值 1,只创建了一行。

【讨论】:

  • 对我的提示的唯一警告是 a) 它保持沉默并且不记录错误,b) 其 11gr2 以后的特定版本,并且我们在 OP 中没有版本信息。但是它确实有效。
  • 它总是取决于实际使用情况,这就是为什么存在多个选项。这只是应该提及的另一个选项。
【解决方案2】:

有一个LOG ERRORS 子句允许您将导致错误的行记录到错误表中 - 此错误表是使用 DBMS 包创建的:

DBMS_ERRLOG.CREATE_ERROR_LOG(table_being_inserted_into ,name_of_table_for_errors ,NULL,NULL,TRUE);

https://docs.oracle.com/cd/B28359_01/appdev.111/b28419/d_errlog.htm

函数签名:

 DBMS_ERRLOG.CREATE_ERROR_LOG (
   dml_table_name            IN VARCHAR2,
   err_log_table_name        IN VARCHAR2 := NULL,
   err_log_table_owner       IN VARCHAR2 := NULL,
   err_log_table_space       IN VARCHAR2 := NULL,
   skip_unsupported          IN BOOLEAN := FALSE);

然后在您的插入语句中以日志错误子句结束它:

LOG ERRORS INTO your_error_table_name ( 'description of your choosing' ) REJECT LIMIT UNLIMITED;

您可以选择接受一个固定数量的拒绝限制,从而允许您在引发真正错误之前指定对错误的有效容忍度,而不是只允许将行放在错误表中。

【讨论】:

    【解决方案3】:

    简单示例插入for loop 并忽略异常:

    begin
      for rc in (select * from <your query> loop
      begin
        insert into t1(...) values (...);
      exceptions when others then 
        null;--ignore any exceptions do nothing 
      end;
      end loop;
    end
    

    其他示例 - 相同的想法,但使用 FORALL 批量操作和 SAVE EXCEPTIONS

    declare
        cursor C is
        select ID, OWNER, OBJECT_NAME, SUBOBJECT_NAME, OBJECT_ID, DATA_OBJECT_ID,
               decode( mod(rownum,100000), 1, rpad('*',20,'*'), OBJECT_TYPE ) object_type,
               CREATED, LAST_DDL_TIME, TIMESTAMP, STATUS, TEMPORARY, GENERATED, SECONDARY
          from big_table;
        type array is table of c%rowtype;
        l_data array;
    
        dml_errors EXCEPTION;
        PRAGMA exception_init(dml_errors, -24381);
        l_errors number;
        l_errno    number;
        l_msg    varchar2(4000);
        l_idx    number;
    begin
        open c;
        loop
            fetch c bulk collect into l_data limit 100;
            begin
                forall i in 1 .. l_data.count SAVE EXCEPTIONS
                    insert into t2 values l_data(i);
            exception
                when DML_ERRORS then
                    l_errors := sql%bulk_exceptions.count;
                    for i in 1 .. l_errors
                    loop
                        l_errno := sql%bulk_exceptions(i).error_code;
                        --do smth with the exceptions
                    end loop;
            end;
            exit when c%notfound;
        end loop;
        close c;
    end;
    

    更多信息请参见 AskTom 和 OraMagazine

    https://asktom.oracle.com/pls/asktom/f?p=100:11:0%3A%3A%3A%3AP11_QUESTION_ID:1422998100346727312

    http://www.oracle.com/technetwork/issue-archive/2012/12-sep/o52plsql-1709862.html

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2018-11-24
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多