Продолжение вставки в 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, вы можете указать, чтобы продолжить загрузку данных, и все "плохие" данные будут пропущены и записаны в отдельный файл.