MERGE与DELETE在目标上与源部分匹配?

时间:2017-09-06 15:53:10

标签: sql-server merge upsert

我们说我有一张带有复合主键的表:

create table FooBar (
   fooId int not null,
   barId int not null,
   status varchar(20) not null,
   lastModified datetime not null, 
   constraint PK_FooBar primary key (fooId, barId)
);

现在我有一些特定fooId的表格数据,可能是这样的:

1, 1, 'ACTIVE'
1, 2, 'INACTIVE'

...我想制作一份MERGE声明,将此表格数据视为仅fooId 1 的权威,删除FooBar中的任何不匹配记录适用于fooId 1,但保留所有<{1}}的记录 1。

例如,我们假设fooId表目前有这些数据:

FooBar

我想用上面提到的两个数据集运行一个merge语句,1, 1, 'ACTIVE', ... (some date, not typing it out) 2, 1, 'ACTIVE', ... 1, 3, 'INACTIVE', ... 2, 2, 'INACTIVE' 中的结果数据集应如下所示:

FooBar

我希望删除行1, 1, 'ACTIVE', ... 2, 1, 'ACTIVE', ... 1, 2, 'INACTIVE', ... 2, 2, 'INACTIVE', ... ,并使用新修改的时间戳更新1, 3, 'INACTIVE'行,并插入1, 1, 'ACTIVE'行。我还希望1, 2, 'INACTIVE' of 2的记录不被修改。

这可以在一个声明中完成吗?如果是这样,怎么样?

1 个答案:

答案 0 :(得分:3)

您可以使用common table expressions作为目标和来源,在这些ctes中,您可以应用过滤器来定义您要使用的行:

-- t = Target = Destination Table = Mirror from Source
-- s = Source = New Data source to merge into Target table 

declare @FooId int = 1;

;with t as (
  select fooId, barId, [status], lastModified 
  from dbo.FooBar f 
  where f.fooId = @FooId
  )
,  s as (
  select fooId, barId, [status], lastModified=sysutcdatetime() 
  from src 
  where src.fooId = @FooId
  )
merge into t with (holdlock) -- holdlock hint for race conditions
using s 
  on (s.FooId = t.FooId and s.barId = t.barId)

    /* If the records matches, update status and lastModified. */
    when matched 
      then update set t.[status] = s.[status], t.lastModified = s.lastModified

    /* If not matched in table, insert the record */
    when not matched by target
      then insert (fooId,  barId,   [status],  lastModified)
        values (s.fooId, s.barId, s.[status], s.lastModified)

    /* If not matched by source, delete the record*/
    when not matched by source
      then delete
 output $action, inserted.*, deleted.*;

rextester演示:http://rextester.com/KRAI9699

返回:

+---------+-------+-------+----------+---------------------+-------+-------+----------+---------------------+
| $action | fooId | barId |  status  |    lastModified     | fooId | barId |  status  |    lastModified     |
+---------+-------+-------+----------+---------------------+-------+-------+----------+---------------------+
| INSERT  | 1     | 2     | INACTIVE | 2017-09-06 16:21:21 | NULL  | NULL  | NULL     | NULL                |
| UPDATE  | 1     | 1     | ACTIVE   | 2017-09-06 16:21:21 | 1     | 1     | ACTIVE   | 2017-09-06 16:21:21 |
| DELETE  | NULL  | NULL  | NULL     | NULL                | 1     | 3     | INACTIVE | 2017-09-06 16:21:21 |
+---------+-------+-------+----------+---------------------+-------+-------+----------+---------------------+

merge参考: