Продолжение вставки в Oracle при возникновении исключения

Я работаю над миграцией данных из устаревшей системы в наше новое приложение (работает на базе данных Oracle, 10gR2). В рамках миграции я работаю над сценарием, который вставляет данные в таблицы, используемые приложением.

Количество импортируемых строк данных исчисляется тысячами, а исходные данные не являются чистыми (неожиданные значения NULL в столбцах NOT NULL и т. Д.). Таким образом, при вставке данных через сценарии, когда возникает такое исключение, сценарий внезапно завершается, и вся транзакция откатывается.

Есть ли способ, с помощью которого я могу продолжить вставку данных, для которых строки чистые? С помощью NVL() или же COALESCE() это не вариант, так как я хотел бы записать строки, вызывающие ошибки, чтобы данные могли быть исправлены для следующего прохода.

РЕДАКТИРОВАТЬ: моя текущая процедура имеет обработчик исключений, я регистрирую первую строку, которая вызывает ошибку. Было бы возможно, чтобы вставки продолжались без прерывания, потому что прямо сейчас для первого обработанного исключения процедура прекращает выполнение.

5 ответов

Решение

Используя PLSQL, вы можете выполнять каждую вставку в отдельной транзакции (COMMIT после каждой) и регистрировать или игнорировать ошибки с помощью обработчика исключений, который продолжает работать.

Если бы объемы данных были выше, построчная обработка в PL/SQL, вероятно, была бы слишком медленной. В этих случаях вы можете использовать протоколирование ошибок DML, описанное здесь.

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

Попробуй это:

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;
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;

Если вы используете sqlldr, вы можете указать, чтобы продолжить загрузку данных, и все "плохие" данные будут пропущены и записаны в отдельный файл.

Другие вопросы по тегам