【问题标题】:Continuing Inserts in Oracle when exception is raised引发异常时继续在 Oracle 中插入
【发布时间】:2010-11-07 03:22:16
【问题描述】:

我正在将数据从旧系统迁移到我们的新应用程序(在 Oracle 数据库,10gR2 上运行)。作为迁移的一部分,我正在编写一个脚本,该脚本将数据插入到应用程序使用的表中。

导入的数据行数达到数千,并且源数据不干净(NOT NULL 列中的意外空值等)。所以在通过脚本插入数据时,每当出现这样的异常时,脚本就突然结束,整个事务回滚。

有没有一种方法可以继续插入行干净的数据? 使用NVL()COALESCE() 不是一个选项,因为我想记录导致错误的行,以便在下一次通过时更正数据。

编辑:我当前的程序有一个异常处理程序,我正在记录导致错误的第一行。插入是否可以继续而不终止,因为现在在第一个处理的异常上,过程终止执行。

【问题讨论】:

    标签: sql oracle exception-handling plsql


    【解决方案1】:

    试试这个:

    for r_row in c_legacy_data loop
      begin
        insert into some_table(a, b, c, ...)
        values (r_row.a, r_row.b, r_row.c, ...);
      exception
        when others then 
          null;  /* or some extra logging */
      end;
    end loop;
    

    【讨论】:

      【解决方案2】:

      如果数据量更大,PL/SQL 中的逐行处理可能会太慢。 在这些情况下,您可以使用 DML 错误记录,描述为here

      CREATE TABLE raises (emp_id NUMBER, sal NUMBER 
         CONSTRAINT check_sal CHECK(sal > 8000));
      
      EXECUTE DBMS_ERRLOG.CREATE_ERROR_LOG('raises', 'errlog');
      
      INSERT INTO raises
         SELECT employee_id, salary*1.1 FROM employees
         WHERE commission_pct > .2
         LOG ERRORS INTO errlog ('my_bad') REJECT LIMIT 10;
      
      SELECT ORA_ERR_MESG$, ORA_ERR_TAG$, emp_id, sal FROM errlog;
      
      ORA_ERR_MESG$               ORA_ERR_TAG$         EMP_ID SAL
      --------------------------- -------------------- ------ -------
      ORA-02290: check constraint my_bad               161    7700
       (HR.SYS_C004266) violated
      

      【讨论】:

      • 只需阅读您提供的链接,DML 验证有一个限制,即在违反唯一约束的情况下无法捕获并因此失败,我遇到了此类错误。无论如何,我没有意识到这一点,并且肯定会在我正在研究的其他转换领域中使用。谢谢。
      【解决方案3】:
      DECLARE
         cursor;
      BEGIN
          loop for each row  in cursor
            BEGIN  -- subBlock begins 
               SAVEPOINT startTransaction;  -- mark a savepoint
       -- do whatever you have do here
               COMMIT;         
            EXCEPTION
               ROLLBACK TO startTransaction;  -- undo changes
            END;  -- subBlock ends
         end loop;
      END;
      

      【讨论】:

        【解决方案4】:

        如果您使用 sqlldr,您可以指定继续加载数据,所有“坏”数据将被跳过并记录在单独的文件中。

        【讨论】:

          【解决方案5】:

          使用 PLSQL,您可以在其自己的事务中执行每个插入(在每个事务之后提交),并使用持续运行的异常处理程序记录或忽略错误。

          【讨论】:

          • 异常处理程序捕获第一个错误,然后退出过程。我怎样才能让它不退出?
          • @Arnshea 是对的 - 将插入插入它自己的块中:BEGIN insert ... EXCEPTION handle_exception END;
          • 谢谢,实现了这一点,对未来有很大帮助。
          猜你喜欢
          • 2011-03-01
          • 1970-01-01
          • 2012-10-19
          • 2021-10-29
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 2020-07-13
          • 1970-01-01
          相关资源
          最近更新 更多