Ведение журнала ошибок с помощью запроса MERGE в Oracle 11 - PullRequest
1 голос
/ 15 апреля 2019

Я использую Oracle 11, и в моей таблице миллионы записей.Я использую оператор MERGE для обновления записей из исходной таблицы в таблицу назначения.

В любой момент при обновлении этих миллионов записей, как я могу регистрировать ошибки для каждой записи?

Например: Я успешно обновил 400 записей, но при обновлении 401-й записи я получаю некоторую ошибку, поэтому в этом случае как мне записать что-то вроде

401-й записи и ее ошибка вызывает

Чтобы из этих миллионов записей я мог определить, для каких записей запрос не удался.

Ответы [ 2 ]

0 голосов
/ 16 апреля 2019

Вы можете регистрировать ошибки в той же самой таблице или таблице по вашему выбору. В приведенном ниже примере я создал таблицу с именем tst_merge и заполнил ее 7 строками данных в 2 столбца column1 и data_to_update для простоты. Чтобы сохранить эту простоту, я создал таблицу с 3-м столбцом для хранения любых ошибок Oracle, но этот столбец может быть в ЛЮБОЙ таблице - предпочтительно в таблице, которая используется для отслеживания этих ошибок.

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

НАСТРОЙКА Таблица и вставьте код данных ниже:

CREATE TABLE "TST_MERGE"
  (
    "COLUMN1" NUMBER,
    "DATA_TO_UPDATE" CHAR(9 BYTE),
    "DB_ERROR" VARCHAR2(200)
  )
;

INSERT INTO tst_merge (column1, data_to_update) VALUES (1001, 'dataInRow');
INSERT INTO tst_merge (column1, data_to_update) VALUES (7001, 'dataInRow');
INSERT INTO tst_merge (column1, data_to_update) VALUES (3001, 'dataInRow');
INSERT INTO tst_merge (column1, data_to_update) VALUES (4001, 'dataInRow');
INSERT INTO tst_merge (column1, data_to_update) VALUES (5001, 'dataInRow');
INSERT INTO tst_merge (column1, data_to_update) VALUES (6001, 'dataInRow');
INSERT INTO tst_merge (column1, data_to_update) VALUES (2001, 'dataInRow');

КОД 1017 * для выполнения того, что вы запрашиваете, приведен ниже. PL / SQL.

DECLARE
  /* Store Error Code and Message so we can log these values into a table */ 
  sql_error_num   NUMBER          :=  0;
  sql_error_msg   VARCHAR2(100)   :=  '';

  CURSOR cur_MergeData IS
    SELECT column1, data_to_update
      /* The below line builds a character n times as the new string to update into the data_to_update field */
      /* Here this is simply going to force the error ORA-12899 'Value Too Large for Column'                 */
      , rpad('L', (to_number(SUBSTR(column1, 1, 1)) * 2), 'L') AS new_string
    FROM tst_merge
    ;

  TYPE t_MergeData IS TABLE OF cur_MergeData%ROWTYPE; /* Type declared based on Cursor     */
  c_MergeData  t_MergeData  :=  t_MergeData();        /* Collection declared based on Type */


BEGIN

  OPEN cur_MergeData;
    FETCH cur_MergeData BULK COLLECT INTO c_MergeData; /* Fill Collection with data from Cursor */
  CLOSE cur_MergeData;

  IF c_MergeData.COUNT > 0 THEN
    FOR r IN c_MergeData.FIRST .. c_MergeData.LAST
    LOOP

      BEGIN
          /* Output row data just for troubleshooting */
          dbms_output.put_line(c_MergeData(r).column1 ||' '|| c_MergeData(r).new_string );

          /* Merge Code */
          MERGE INTO tst_merge tm USING
          (
          SELECT column1, data_to_update
          FROM /* When Merging into the same table the MERGE INSERT ONLY works if a record is returned. */
               /* The dual table forces a record with columns values of NULL to be returned if NO MATCH is found. */
            (SELECT 1 AS fake FROM dual) d
            LEFT JOIN tst_merge t ON t.column1 = c_MergeData(r).column1
          ) m ON (m.column1 = tm.column1)

          WHEN MATCHED THEN       

          UPDATE SET data_to_update = c_MergeData(r).new_string
          WHERE column1 = c_MergeData(r).column1

          WHEN NOT MATCHED THEN

          INSERT (column1, data_to_update)
          VALUES (c_MergeData(r).column1, c_MergeData(r).new_string)
          ;

      EXCEPTION       
        WHEN OTHERS THEN 
          sql_error_num :=  SQLCODE;
          sql_error_msg :=  SQLERRM;

          DBMS_OUTPUT.put_line('Error '||TO_CHAR(sql_error_num)||': '||sql_error_msg);

          UPDATE tst_merge SET db_error = ('Error '||TO_CHAR(sql_error_num)||': '||sql_error_msg)
          WHERE column1 = c_MergeData(r).column1;

      END;          

    END LOOP;
  END IF;

END
;

Gif ниже, чтобы увидеть его в действии

enter image description here

0 голосов
/ 16 апреля 2019

Вы не можете выбрать свою собственную ошибку, но вы можете использовать error_logging_clause. См. Документацию Oracle по https://docs.oracle.com/cd/B28359_01/server.111/b28286/statements_9016.htm#SQLRF01606.

Сначала нужно создать таблицу журнала ошибок с помощью DBMS_ERRLOG. В конце вашего заявления о слиянии вам нужно добавить

LOG ERRORS INTO <<errorLogTableName>> 
...