T-SQL :合并插入旧值和新值然后进行更改

T-SQL : merge insert old and new value then make changes

这是我第一次使用 T-SQL Merge,我一直在尝试使用以下条件编写存储过程:

  1. 如果存在记录,则将 Id、旧值(更新前)和新值插入 Changes table,然后从 [= 更新旧值15=]

  2. 如果记录不存在,则将 Id 插入 Changes,旧值和新值均为空,然后在 Affected

    中插入新记录
  3. 如果记录不匹配,则将 Id、旧值(删除前的值)和空值插入 Changes 中作为新值,然后删除记录

这是我用过的 table

CREATE TABLE Affected
(
    [Id] int IDENTITY(1,1) NOT NULL,
    [ZoneId] int NOT NULL,
    [Name] varchar(100) NOT NULL,
    [Value] varchar(100)
)

CREATE TABLE Changes
(
    [AffectedId] int NOT NULL,
    [OldValue] varchar(100),
    [NewValue] varchar(100)
)

这是我的存储过程,它将两个区域 ID 作为输入参数

CREATE PROCEDURE spAffectChanges
    @ZoneId1 int,
    @ZoneId2 int
AS
    IF(@ZoneId1 < 10)
    BEGIN
        ;WITH fromQ AS 
        (
            SELECT DISTINCT Name, Value 
            FROM Affected 
            WHERE ZoneId = @ZoneId1 AND Name NOT IN ('aaa', 'bbb', 'ccc')
        ), toQ AS
        (
            SELECT DISTINCT Name, Value 
            FROM Affected 
            WHERE ZoneId = @ZoneId2 AND Name NOT IN ('aaa', 'bbb', 'ccc')
        )
        MERGE toQ
        USING fromQ ON (toQ.Name = fromQ.Name)

        WHEN MATCHED AND fromQ.Value<>toQ.Value THEN
            ----first insert
            INSERT INTO Changes (AffectedId, OldValue, NewValue)
            VALUES(toQ.Id, toQ.Value, fromQ.Value)
            ----then update
            UPDATE SET toQ.Value=fromQ.Value

        WHEN NOT MATCHED BY toQ THEN
            ----first insert
            INSERT INTO Changes (AffectedId, OldValue, NewValue)
            VALUES(toQ.Id, '', fromQ.Value)
            ----second insert 
            INSERT (Name, Zone, Value)
            VALUES (fromQ.Name, @ZoneId1, fromQ.Value)

        WHEN NOT MATCHED BY fromQ THEN
            ----first insert
            INSERT INTO Changes (AffectedId, OldValue, NewValue)
            VALUES(toQ.Id, toQ.Value, '')
            ----then delete
            DELETE
    END

有没有办法对 Affected 执行插入更改和 Update/Insert/Delete?

提前致谢

您可以使用 OUTPUT 子句来执行此操作。

备注:

  • MERGE 需要 分号终止符。 ;WITH 很傻,; 不是开始符,它应该放在每个命令的末尾
  • WHEN NOT MATCHED 的选项是 BY SOURCEBY TARGET(这是默认值)
  • 我不太明白你如何在目标上设置 DISTINCT,我不认为这是允许的,也不认为这样做有什么意义。
        WITH fromQ AS 
        (
            SELECT DISTINCT Name, Value 
            FROM Affected 
            WHERE ZoneId = @ZoneId1 AND Name NOT IN ('aaa', 'bbb', 'ccc')
        ), toQ AS
        (
            SELECT Name, Value 
            FROM Affected 
            WHERE ZoneId = @ZoneId2 AND Name NOT IN ('aaa', 'bbb', 'ccc')
        )
        MERGE toQ
        USING fromQ ON (toQ.Name = fromQ.Name)

        WHEN MATCHED AND fromQ.Value <> toQ.Value THEN
            UPDATE
                SET toQ.Value = fromQ.Value

        WHEN NOT MATCHED BY TARGET THEN
            INSERT (Name, Zone, Value)
            VALUES (fromQ.Name, @ZoneId1, fromQ.Value)

        WHEN NOT MATCHED BY SOURCE THEN
            DELETE

        OUTPUT inserted.Id, ISNULL(deleted.Value, ''), ISNULL(inserted.Value, '')
            INTO Changes (AffectedId, OldValue, NewValue)
        ;