Таблица Temp для вставки или обновления главной таблицы с аудитом и протоколированием

Я должен выбирать записи из temptable и вставлять или обновлять до mastertable . Если одно поле изменено, мне нужно обновить таблицу history следующим образом:

  • RecordID
  • ColumnChanged
  • OldValue
  • NewValue

Во время выполнения вставки или обновления из temptable к mastertable любые ошибки, возникающие из-за нарушений внешнего ключа (или любых других ошибок), должны регистрироваться в таблице error .

Мне нужна история изменений и протоколирования ошибок, так что, если одна запись не удалась, я могу снова запустить процесс.

Как это сделать с помощью T-SQL? Любые фрагменты кода будут полезны.

Вот столбец таблиц, с которыми я работаю:

  1. TempTable
    COL1, COL2, COL3, COL4, COL5

  2. MASTERTABLE
    COL1, COL2, COL3

  3. ИСТОРИЯ
    RecordID, ColumnChanged, OldValue, NewValue

  4. ОШИБКА
    ErrorCode, ErrorMsg

Мне нужно использовать курсор, поскольку мне нужно прокручивать каждую запись при выполнении вставок или обновлений и регистрировать любые ошибки, которые происходят во время вставки или обновления из-за плохих данных.

Мне нужно отметить flagcolumn как «Y» для всех успешных вставок или обновлений и «N» для всех неудачных записей, чтобы я мог перезагрузить их снова после исправления данных.

Я уже использовал sqlbulkcopy для загрузки данных в temptable .

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

Схема:

 CREATE TABLE dbo.HistoryTable ( HistoryTableID INT IDENTITY(1,1) PRIMARY KEY NOT NULL, PKRecordID INT NOT NULL, ColumnChanged VARCHAR(50) NOT NULL, OldValue VARCHAR(10) NOT NULL, NewValue VARCHAR(10) NOT NULL, ChangedDate DATETIME NOT NULL DEFAULT (GETDATE()) ) GO CREATE TABLE dbo.ForeignKeyTableCOL2 (COL2 VARCHAR(10) PRIMARY KEY NOT NULL) GO CREATE TABLE dbo.ForeignKeyTableCOL1 (COL1 VARCHAR(10) PRIMARY KEY NOT NULL) GO CREATE TABLE dbo.ErrorTable ( ErrorTableID INT IDENTITY(1,1) PRIMARY KEY NOT NULL, PKRecordID INT NOT NULL, TableName VARCHAR(50) NOT NULL, TablePK INT NOT NULL, ErrorDateTime DATETIME NOT NULL DEFAULT (GETDATE()), ErrorCode INT NOT NULL, ErrorMsg VARCHAR(2000) NOT NULL ) GO CREATE TABLE dbo.TempTable ( TempTableID INT IDENTITY(1,1) NOT NULL, PKRecordID INT NOT NULL, COL1 VARCHAR(10) NOT NULL, COL2 VARCHAR(10) NOT NULL, COL3 VARCHAR(10) NOT NULL, COL4 VARCHAR(10) NOT NULL, COL5 VARCHAR(10) NOT NULL, Success CHAR(1) NOT NULL DEFAULT ('N') ) GO CREATE TABLE dbo.MasterTable ( PKRecordID INT NOT NULL, COL1 VARCHAR(10) NOT NULL, COL2 VARCHAR(10) NOT NULL, COL3 VARCHAR(10) NOT NULL, COL4 VARCHAR(10) NOT NULL, COL5 VARCHAR(10) NOT NULL ) GO ALTER TABLE dbo.MasterTable WITH CHECK ADD CONSTRAINT FK_MasterTable_ForeignKeyTableCOL1 FOREIGN KEY(COL1) REFERENCES dbo.ForeignKeyTableCOL1 (COL1) ALTER TABLE dbo.MasterTable CHECK CONSTRAINT FK_MasterTable_ForeignKeyTableCOL1 ALTER TABLE dbo.MasterTable WITH CHECK ADD CONSTRAINT FK_MasterTable_ForeignKeyTableCOL2 FOREIGN KEY(COL2) REFERENCES dbo.ForeignKeyTableCOL2 (COL2) ALTER TABLE dbo.MasterTable CHECK CONSTRAINT FK_MasterTable_ForeignKeyTableCOL2 INSERT dbo.ForeignKeyTableCOL1 (COL1) VALUES ('A'), ('B'), ('C') INSERT dbo.ForeignKeyTableCOL2 (COL2) VALUES ('A'), ('B'), ('C') INSERT dbo.TempTable (PKRecordID, COL1, COL2, COL3, COL4, COL5) VALUES (1, 'A', 'A', 'A', 'A', 'A'), (2, 'B', 'B', 'B', 'B', 'B'), (3, 'C', 'C', 'C', 'C', 'C'), (1, 'D', 'A', 'A', 'A', 'A'), (1, 'A', 'D', 'A', 'A', 'A'), (1, 'D', 'D', 'A', 'A', 'A'), (2, 'A', 'B', 'B', 'B', 'B'), (3, 'A', 'B', 'C', 'C', 'C'), (4, 'D', 'D', 'D', 'D', 'D') 

Запрос:

 SET NOCOUNT ON; DECLARE @PKRecordID INT , @COL1 VARCHAR(10) , @COL2 VARCHAR(10) , @COL3 VARCHAR(10) , @COL4 VARCHAR(10) , @COL5 VARCHAR(10) , @TempTableID INT , @New_Row XML , @Old_Row XML DECLARE cur CURSOR LOCAL FAST_FORWARD READ_ONLY FOR SELECT t.TempTableID , t.PKRecordID , t.COL1 , t.COL2 , t.COL3 , t.COL4 , t.COL5 , New_Row = CAST('<r><s>' + t.COL1 + '</s><s>' + t.COL2 + '</s><s>' + t.COL3 + '</s><s>' + t.COL4 + '</s><s>' + t.COL5 + '</s></r>' AS XML) , Old_Row = CAST('<r><s>' + m.COL1 + '</s><s>' + m.COL2 + '</s><s>' + m.COL3 + '</s><s>' + m.COL4 + '</s><s>' + m.COL5 + '</s></r>' AS XML) FROM dbo.TempTable t LEFT JOIN dbo.MasterTable m ON t.PKRecordID = m.PKRecordID OPEN cur FETCH NEXT FROM cur INTO @TempTableID , @PKRecordID , @COL1 , @COL2 , @COL3 , @COL4 , @COL5 , @New_Row , @Old_Row WHILE @@FETCH_STATUS = 0 BEGIN BEGIN TRY IF @Old_Row IS NOT NULL BEGIN UPDATE dbo.MasterTable SET COL1 = @COL1 , COL2 = @COL2 , COL3 = @COL3 , COL4 = @COL4 , COL5 = @COL5 WHERE PKRecordID = @PKRecordID INSERT dbo.HistoryTable ( PKRecordID , ColumnChanged , OldValue , NewValue ) SELECT @PKRecordID , 'COL' + CAST(new_id AS VARCHAR(5)) , old_value , new_value FROM ( SELECT new_value = n.value('(.)1', 'VARCHAR(10)') , new_id = 1 + n.value('for $i in . return count(../*. << $i)', 'int') , old_value = o.value('(.)1', 'VARCHAR(10)') , old_id = 1 + o.value('for $i in . return count(../*. << $i)', 'int') FROM (SELECT a = 1) d CROSS APPLY @New_Row.nodes('/r/s') t(n) CROSS APPLY @Old_Row.nodes('/r/s') k(o) ) data WHERE new_id = old_id AND NULLIF(new_value, '') != NULLIF(old_value, '') UPDATE dbo.TempTable SET Success = 'Y' WHERE TempTableID = @TempTableID END ELSE BEGIN INSERT dbo.MasterTable ( PKRecordID , COL1 , COL2 , COL3 , COL4 , COL5 ) SELECT @PKRecordID , @COL1 , @COL2 , @COL3 , @COL4 , @COL5 UPDATE dbo.TempTable SET Success = 'Y' WHERE TempTableID = @TempTableID END END TRY BEGIN CATCH INSERT dbo.ErrorTable ( PKRecordID , TableName , TablePK , ErrorDateTime , ErrorCode , ErrorMsg ) SELECT @PKRecordID , 'TempTable' , @TempTableID , GETDATE() , ERROR_NUMBER() , ERROR_MESSAGE() END CATCH FETCH NEXT FROM cur INTO @TempTableID , @PKRecordID , @COL1 , @COL2 , @COL3 , @COL4 , @COL5 , @New_Row , @Old_Row END CLOSE cur DEALLOCATE cur 

И это может быть полезно для вас:

 CREATE TRIGGER ... ON ... INSTEAD OF INSERT, UPDATE AS BEGIN SET NOCOUNT ON SET XACT_ABORT ON DECLARE @DocumentUID UNIQUEIDENTIFIER ... DECLARE cur CURSOR FORWARD_ONLY READ_ONLY LOCAL FOR SELECT DocumentUID, ... FROM INSERTED OPEN cur FETCH NEXT FROM cur INTO @DocumentUID, ... WHILE @@FETCH_STATUS = 0 BEGIN DECLARE @BeforeChange NVARCHAR(MAX) , @AfterChange NVARCHAR(MAX) SELECT @BeforeChange = ( SELECT * FROM DELETED WHERE DocumentUID = @DocumentUID FOR XML RAW, ROOT ) , @AfterChange = ( SELECT * FROM INSERTED WHERE DocumentUID = @DocumentUID FOR XML RAW, ROOT ) IF EXISTS( SELECT 1 FROM dbo.Documents WHERE DocumentUID = @DocumentUID ) BEGIN INSERT INTO ... SELECT @BeforeChange, @AfterChange END ELSE BEGIN ... END FETCH NEXT FROM cur INTO @DocumentUID, ... END CLOSE cur DEALLOCATE cur END 

Настройте нашу схему и таблицы для тестирования

 SET NOCOUNT ON IF OBJECT_ID('TempTable', 'U') IS NOT NULL DROP TABLE TempTable; IF OBJECT_ID('MasterTable', 'U') IS NOT NULL DROP TABLE MasterTable; IF OBJECT_ID('ForeignKeyTableCOL1', 'U') IS NOT NULL DROP TABLE ForeignKeyTableCOL1; IF OBJECT_ID('ForeignKeyTableCOL2', 'U') IS NOT NULL DROP TABLE ForeignKeyTableCOL2; IF OBJECT_ID('HistoryTable', 'U') IS NOT NULL DROP TABLE HistoryTable; IF OBJECT_ID('ErrorTable', 'U') IS NOT NULL DROP TABLE ErrorTable; CREATE TABLE ForeignKeyTableCOL1 (COL1 varchar(10) PRIMARY KEY) CREATE TABLE ForeignKeyTableCOL2 (COL2 varchar(10) PRIMARY KEY) CREATE TABLE TempTable (TempTableID int IDENTITY(1,1), PKRecordID int, COL1 varchar(10), COL2 varchar(10), COL3 varchar(10), COL4 varchar(10), COL5 varchar(10), Success char(1)) CREATE TABLE MasterTable (PKRecordID int PRIMARY KEY, COL1 varchar(10), COL2 varchar(10), COL3 varchar(10), COL4 varchar(10), COL5 varchar(10)) ALTER TABLE MasterTable ADD CONSTRAINT FK_MasterTable_ForeignKeyTableCOL1 FOREIGN KEY (COL1) REFERENCES ForeignKeyTableCOL1 (COL1) ALTER TABLE MasterTable ADD CONSTRAINT FK_MasterTable_ForeignKeyTableCOL2 FOREIGN KEY (COL2) REFERENCES ForeignKeyTableCOL2 (COL2) CREATE TABLE HistoryTable (HistoryTableID int IDENTITY(1,1) PRIMARY KEY, PKRecordID int, ColumnChanged varchar(50), OldValue varchar(10), NewValue varchar(10)) CREATE TABLE ErrorTable (ErrorTableID int IDENTITY(1,1) PRIMARY KEY, PKRecordID int, TableName varchar(50), TablePK int, ErrorDateTime datetime, ErrorCode int, ErrorMsg nvarchar(4000)) GO INSERT ForeignKeyTableCOL1 SELECT 'A' UNION SELECT 'B' UNION SELECT 'C' INSERT ForeignKeyTableCOL2 SELECT 'A' UNION SELECT 'B' UNION SELECT 'C' INSERT TempTable SELECT 1, 'A', 'A', 'A', 'A', 'A', 'N' INSERT TempTable SELECT 2, 'B', 'B', 'B', 'B', 'B', 'N' INSERT TempTable SELECT 3, 'C', 'C', 'C', 'C', 'C', 'N' INSERT TempTable SELECT 1, 'D', 'A', 'A', 'A', 'A', 'N' INSERT TempTable SELECT 1, 'A', 'D', 'A', 'A', 'A', 'N' INSERT TempTable SELECT 1, 'D', 'D', 'A', 'A', 'A', 'N' INSERT TempTable SELECT 2, 'A', 'B', 'B', 'B', 'B', 'N' INSERT TempTable SELECT 3, 'A', 'B', 'C', 'C', 'C', 'N' INSERT TempTable SELECT 4, 'D', 'D', 'D', 'D', 'D', 'N' SET NOCOUNT OFF 

Выполнять INSERTS и UPDATES с помощью аудита / регистрации ошибок

 DECLARE @PKRecordID int, @COL1 varchar(10), @COL2 varchar(10), @COL3 varchar(10), @COL4 varchar(10), @COL5 varchar(10), @TempTableID int DECLARE @PKRecordID_OLD int, @COL1_OLD varchar(10), @COL2_OLD varchar(10), @COL3_OLD varchar(10), @COL4_OLD varchar(10), @COL5_OLD varchar(10) DECLARE temp_cursor CURSOR FOR SELECT TempTableID, PKRecordID, COL1, COL2, COL3, COL4, COL5 FROM TempTable ORDER BY TempTableID; OPEN temp_cursor FETCH NEXT FROM temp_cursor INTO @TempTableID, @PKRecordID, @COL1, @COL2, @COL3, @COL4, @COL5 WHILE @@FETCH_STATUS = 0 BEGIN --SELECT @idx, @COL1, @COL2, @COL3, @COL4, @COL5 BEGIN TRY IF EXISTS (SELECT * FROM MasterTable WHERE PKRecordID = @PKRecordID) BEGIN SELECT @COL1_OLD = COL1 ,@COL2_OLD = COL2 ,@COL3_OLD = COL3 ,@COL4_OLD = COL4 ,@COL5_OLD = COL5 FROM MasterTable WHERE PKRecordID = @PKRecordID UPDATE MasterTable SET COL1 = @COL1 ,COL2 = @COL2 ,COL3 = @COL3 ,COL4 = @COL4 ,COL5 = @COL5 WHERE PKRecordID = @PKRecordID INSERT HistoryTable (PKRecordID, ColumnChanged, OldValue, NewValue) SELECT @PKRecordID, 'COL1', @COL1_OLD, @COL1 WHERE EXISTS (SELECT @COL1 EXCEPT SELECT @COL1_OLD) INSERT HistoryTable (PKRecordID, ColumnChanged, OldValue, NewValue) SELECT @PKRecordID, 'COL2', @COL2_OLD, @COL2 WHERE EXISTS (SELECT @COL2 EXCEPT SELECT @COL2_OLD) INSERT HistoryTable (PKRecordID, ColumnChanged, OldValue, NewValue) SELECT @PKRecordID, 'COL3', @COL3_OLD, @COL3 WHERE EXISTS (SELECT @COL3 EXCEPT SELECT @COL3_OLD) INSERT HistoryTable (PKRecordID, ColumnChanged, OldValue, NewValue) SELECT @PKRecordID, 'COL4', @COL4_OLD, @COL4 WHERE EXISTS (SELECT @COL4 EXCEPT SELECT @COL4_OLD) INSERT HistoryTable (PKRecordID, ColumnChanged, OldValue, NewValue) SELECT @PKRecordID, 'COL5', @COL5_OLD, @COL5 WHERE EXISTS (SELECT @COL5 EXCEPT SELECT @COL5_OLD) UPDATE TempTable SET Success = 'Y' WHERE TempTableID = @TempTableID END ELSE BEGIN INSERT MasterTable (PKRecordID, COL1, COL2, COL3, COL4, COL5) SELECT @PKRecordID, @COL1, @COL2, @COL3, @COL4, @COL5 UPDATE TempTable SET Success = 'Y' WHERE TempTableID = @TempTableID END END TRY BEGIN CATCH INSERT ErrorTable (PKRecordID, TableName, TablePK, ErrorDateTime, ErrorCode, ErrorMsg) SELECT @PKRecordID, 'TempTable', @TempTableID, GETDATE(), ERROR_NUMBER(), ERROR_MESSAGE() END CATCH FETCH NEXT FROM temp_cursor INTO @TempTableID, @PKRecordID, @COL1, @COL2, @COL3, @COL4, @COL5 END CLOSE temp_cursor; DEALLOCATE temp_cursor; -- VIEW OUTPUT SELECT * FROM MasterTable SELECT * FROM ErrorTable SELECT * FROM HistoryTable SELECT * FROM TempTable 
Давайте будем гением компьютера.