Я испытываю большие затруднения при попытке реплицировать ведение журнала, как я это делал в 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