我必须从temptable
中选择记录并插入或更新到mastertable
。如果更改了单个字段,那么我需要使用以下内容更新history
表:
RecordID
ColumnChanged
OldValue
NewValue
执行从temptable
到mastertable
的插入或更新时,由于外键冲突(或任何其他错误)而发生的任何错误都应记录到error
表
我需要更改和记录错误的历史记录,这样如果单个记录失败,我可以重新运行该过程。
如何使用T-SQL执行此操作?任何代码段都会有所帮助。
以下是我正在使用的表格列:
不是Temptable
COL1,COL2,COL3,COL4,COL5
MASTERTABLE
COL1,COL2,COL3
记录
RecordID,ColumnChanged,OldValue,NewValue
错误
ErrorCode,ErrorMsg
我需要使用游标,因为我需要在执行插入或更新时循环遍历每个记录,并记录因插入或更新而导致的错误数据。
我需要将flagcolumn
标记为所有成功插入或更新的“Y”,并将所有失败记录标记为“N”,以便我可以在更正数据后重新加载它们。
我已使用sqlbulkcopy
将数据加载到temptable
。
答案 0 :(得分: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
答案 1 :(得分: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