SQL Сервер - Как мне создать / зафиксировать записи в журнале во время запущенного процесса, который потенциально будет ROLLEDBACK - PullRequest
0 голосов
/ 17 апреля 2020

Я испытываю большие затруднения при попытке реплицировать ведение журнала, как я это делал в Oracle, используя PRAGRMA AUTOMOUS_TRANSACTION, которая позволяет вам ЗАПИСАТЬ записи в таблицу LOG, а НЕ ПОДДЕРЖАТЬ другие операции DML. Я бился головой о том, как опытные серверы SQL регистрируют успех или ошибки своих программ / процессов базы данных. В основном, как опытные парни T- SQL регистрируются в середине активной программы T- SQL? Другой способ выразить это ... У меня ОГРОМНЫЙ процесс, который НЕ ОБЯЗАН, пока весь процесс не будет выполнен без критических ошибок, но мне все еще нужно регистрировать ВСЕ ошибки и, если это критическая ошибка, тогда ROLLBACK весь процесс, но мне все еще нужен Журналы.

Использование MERGE в качестве примера, демонстрирующего мою неспособность зафиксировать некоторые записи, но откатывать другие ...

В приведенном ниже сценарии есть две именованные транзакции (1. sourceData, 2. mainProcess) ... Это моя первая попытка достичь этой цели. Сначала скрипт вставляет записи с использованием 1-й транзакции в таблицу без COMMIT. Затем в транзакции 2 в блоке MERGE я вставляю записи в таблицу назначения и в таблицу журнала, и я выполняю транзакцию 2 (mainProcess).

Затем я ROLLING BACK 1-й названной транзакцией (sourceData) ..

Проблема в том, что ... ВСЕ возвращается ROLLED, даже если я явно ПОДТВЕРДИЛ транзакцию mainProcess.

GO
/* temp table to simulate Log Table */
IF OBJECT_ID('tempdb..#LogTable') IS NULL
    CREATE TABLE #LogTable  
    (   Action                  VARCHAR(50),
        primaryID               INT,
        secondaryID             INT,
        CustomID                INT,
        Note                    VARCHAR(200),
        ConvDate                DATE
    ) --DROP TABLE IF EXISTS #LogTable;
;  /* SELECT * FROM #LogTable; TRUNCATE TABLE #LogTable; */

/* SELECT * FROM #ProductionSrcTable */
IF OBJECT_ID('tempdb..#ProductionSrcTable') IS NULL
    CREATE TABLE #ProductionSrcTable(   primaryKey INT, contactName VARCHAR(200), sourceKey    INT  )
; --DROP TABLE IF EXISTS #ProductionSrcTable; TRUNCATE TABLE #ProductionSrcTable;

/* SELECT * FROM #ProductionDestTable */
IF OBJECT_ID('tempdb..#ProductionDestTable') IS NULL
    CREATE TABLE #ProductionDestTable(  primaryKey INT, contactName VARCHAR(200), secondaryKey INT  )
; --DROP TABLE IF EXISTS #ProductionDestTable; TRUNCATE TABLE #ProductionDestTable;

GO

/* Insert some fake data into Source Table */
BEGIN TRAN sourceData

BEGIN TRY
    INSERT INTO #ProductionSrcTable
        SELECT 1001 AS primaryKey, 'Jason' AS contactName, 789105 AS sourceKey UNION ALL
        SELECT 1002 AS primaryKey, 'Jane'  AS contactName, 789185 AS sourceKey UNION ALL
        SELECT 1003 AS primaryKey, 'Sam'   AS contactName, 788181 AS sourceKey UNION ALL
        SELECT 1004 AS primaryKey, 'Susan' AS contactName, 681181 AS sourceKey
    ;
END TRY

BEGIN CATCH
    ROLLBACK TRANSACTION sourceData
END CATCH

/* COMMIT below is purposely commented out in order to Test */
--COMMIT TRANSACTION sourceData

GO

BEGIN TRAN mainProcess

    DECLARE @insertedRecords    INT = 0,
            @CustomID           INT = 2,
            @Note               VARCHAR(200) = 'Test Temp DB Record Population via OUTPUT Clause',
            @ConvDate           DATE = getDate()
    ;

BEGIN TRY

    MERGE INTO #ProductionDestTable AS dest
    USING 

    (
        SELECT src.primaryKey, src.contactName, src.sourceKey FROM #ProductionSrcTable src

    ) AS src ON src.primaryKey = dest.primaryKey AND src.sourceKey = dest.secondaryKey

    WHEN NOT MATCHED BY TARGET 
    THEN
        INSERT --INTO ProductionDestTable
        (   primaryKey, contactName, secondaryKey               )
        VALUES
        (   src.primaryKey, src.contactName, src.sourceKey      )


    /* Insert Output in Log Table  */
    OUTPUT $action, inserted.primaryKey, src.sourceKey, @CustomID, @Note, @ConvDate INTO #LogTable;


    ; /* END MERGE */

    /* Store the number of inserted Records into the insertedRecords variable */
    SET @insertedRecords = @@ROWCOUNT;

    END TRY

    BEGIN CATCH
        ROLLBACK TRANSACTION mainProcess
    END CATCH
;

--ROLLBACK TRANSACTION mainProcess
COMMIT TRANSACTION mainProcess

ROLLBACK TRANSACTION sourceData

PRINT 'Records Inserted:' + CAST(@insertedRecords AS VARCHAR);

/* END  */

--SELECT @@TRANCOUNT
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...