Temp table to Master table insert or update with auditing and logging

前端 未结 2 1595
难免孤独
难免孤独 2021-01-19 05:34

I have to select the records from temptable and insert or update to mastertable. If a single field is changed, then I need to update my histo

相关标签:
2条回答
  • 2021-01-19 06:10

    Setup our schema and tables for testing

    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
    

    Execute the INSERTS and UPDATES with audit/error logging

    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
    
    0 讨论(0)
  • 2021-01-19 06:24

    Try this one -

    Schema:

    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')
    

    Query:

    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
    

    And this possible be helpful for you:

    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
    
    0 讨论(0)
提交回复
热议问题