4

からレコードを選択し、temptableに挿入または更新する必要がありmastertableます。単一のフィールドが変更された場合history、次のようにテーブルを更新する必要があります。

  • RecordID
  • ColumnChanged
  • OldValue
  • NewValue

temptableからへの挿入または更新を実行している間、mastertable外部キー違反(またはその他のエラー)が原因で発生したエラーはすべて、errorテーブルに記録する必要があります。

変更の履歴とエラーのログ記録が必要です。これにより、1つのレコードに障害が発生した場合に、プロセスを再実行できます。

T-SQLを使用してこれを行うにはどうすればよいですか?コードスニペットはどれでも役に立ちます。

これが私が扱っているテーブルの列です:

  1. TEMPTABLE
    COL1、COL2、COL3、COL4、COL5


  2. マスターテーブルCOL1、COL2、COL3

  3. HISTORY
    RecordID、ColumnChanged、OldValue、NewValue

  4. ERROR
    ErrorCode、ErrorMsg

挿入または更新を実行するときに各レコードをループし、データの不良が原因で挿入または更新中に発生したエラーをログに記録する必要があるため、カーソルを使用する必要があります。

flagcolumn挿入または更新が成功した場合はすべて「Y」、失敗したすべてのレコードを「N」としてマークして、データの修正後に再度リロードできるようにする必要があります。

私はすでにsqlbulkcopyデータをにロードするために使用しましたtemptable

4

2 に答える 2

2

これを試してください-

スキーマ:

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
于 2013-05-06T15:24:24.107 に答える
0

テスト用にスキーマとテーブルを設定します

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
于 2013-05-04T21:25:55.873 に答える