为什么upserted INSERTED.ID和DELETED.ID都包含MERGE之后的值?

时间:2017-04-27 11:20:39

标签: sql-server tsql sql-server-2016

令人惊讶的是,我无法在Google上找到答案,尽管我的术语可能不合适。我也没有看到关于MDSN的解释。

使用以下代码执行简单的MERGE

DECLARE @tbl_1 TABLE (ID int IDENTITY(1,1), person nvarchar(20));
DECLARE @tbl_2 TABLE (ID int IDENTITY(1,1), person nvarchar(20));   
INSERT INTO @tbl_1 (person) VALUES ('Bob'),('Ted'),('Brian');
INSERT INTO @tbl_2 (person) VALUES ('Bob'),('Ted'),('Peter');

MERGE INTO  
    @tbl_2 as tgt
USING 
    @tbl_1 as src
ON
    (tgt.person = src.person)
WHEN MATCHED THEN 
    UPDATE SET tgt.person = src.person
WHEN NOT MATCHED BY TARGET THEN
    INSERT (person) VALUES (src.person)
WHEN NOT MATCHED BY SOURCE THEN
    DELETE
OUTPUT 
    $ACTION,
    DELETED.ID,
    DELETED.person AS PersonOld,
    INSERTED.ID,
    INSERTED.person AS PersonNew;

在结果中,我看到每行的ID值都针对INSERTEDDELETED行显示,其中UPDATE已经发生:

Post-merge

为什么这样好?我希望更新后DELETED.IDNULLINSERTED.ID代表 UPSERTED 行(我过去曾使用过触发器,并假设{{ 1}}将遵循相同的方法。)

1 个答案:

答案 0 :(得分:3)

因为您似乎知道MERGEUPSERT(更新+插入)。

现在,INSERTED表记录了由INSERT&添加的行添加的行的信息。 UPDATE个命令和DELETED表包含已更新或删除的行的信息。

看看MSDN documentation on how to "Use the inserted and deleted Tables"

  

插入表在INSERT期间存储受影响行的副本   和UPDATE语句。在插入或更新事务期间,新的   行被添加到插入的表和触发器表中。该   inserted表中的行是触发器中新行的副本   表

  

更新事务类似于删除操作后跟一个   插入操作;先将旧行复制到已删除的表中,   然后将新行复制到触发器表和   插表。

<强>更新

我看到你评论了你的问题,你发现这个操作实际上是一个 delsert 。你可能会想到为什么会这样?

考虑如何在SQL Server中存储数据。它存储在8KB页面上,当您更新数据页面中包含的列中的信息时,整个数据页面将被重写,因此基本上是 delsert

INSERT相同的是,新行将进入数据页面(并且可能会生成页面拆分 - 但这是另一个主题)并且必须重写整个数据页面。