TSQL合并:处于“开​​启”状态的目标表

时间:2019-01-04 12:15:36

标签: sql-server tsql merge

我想使用merge,并且受到reference关于ON加入条件的警告的威胁:

  

仅指定目标表中的列是很重要的   用于匹配目的。也就是说,从   目标表,将其与   源表。不要尝试通过过滤来提高查询性能   在ON子句中淘汰目标表中的行,例如通过指定   并且不是target_table.column_x =值。这样做可能会返回意外   和错误的结果。

这是一个例子:

-- drop table trg
create table trg(department int not null,student int not null,name nvarchar(20))
alter table trg add constraint PK_trg primary key clustered (department,student)
insert trg values (12,0,'Tony'),(12,1,'Helen'),(55,0,'Tony'),(55,1,'Helen')

-- drop table src 
go
create table src(student int not null,name nvarchar(20)) 
go
alter table src add constraint PK_src primary key clustered (student) 
go
insert src values (0,'Antony'),(1,'Helen'),(2,'Mike')

select * from trg
select * from src

trg表

+------------+---------+-------+
| department | student | name  |
+------------+---------+-------+
|         12 |       0 | Tony  |
|         12 |       1 | Helen |
|         55 |       0 | Tony  |
|         55 |       1 | Helen |
+------------+---------+-------+

在两个系中有2个学生(请忽略2nf违规,第三个列也应该依赖系,但我现在想不出一个例子)。

现在,我们得到了一个src表,该表具有有关部门12的信息 only

+---------+--------+
| student |  name  |
+---------+--------+
|       0 | Antony |
|       1 | Helen  |
|       2 | Mike   |
+---------+--------+

...,我们想用srcmerge中添加此信息。

使用此:

merge trg using src on trg.student=src.student and trg.department=12
    when matched then update set name=src.name
    when not matched by target then insert values (12,src.student,src.name)
;

符合我们的预期。 trg表现在具有所需的输出:

+------------+---------+--------+
| department | student |  name  |
+------------+---------+--------+
|         12 |       0 | Antony |
|         12 |       1 | Helen  |
|         12 |       2 | Mike   |
|         55 |       0 | Tony   |
|         55 |       1 | Helen  |
+------------+---------+--------+

我们可以看到第12部门的Tony被更名为Antony,第12部门插入了Mike,其他都没有发生。这是通过违反参考警告而做出的。可以吗?

我想它可以改写为:

merge trg using src on trg.student=src.student
    when matched and trg.department=12 then update set name=src.name
    when not matched by target then insert values (12,src.student,src.name);

这确实也可以正常工作。

是与警告错误相抵触的第一种方法,或者是不良做法?为什么?

1 个答案:

答案 0 :(得分:3)

发出警告的原因是,如果源表中包含类似55,0,Tony的内容,则将其视为不匹配内容,并转到INSERT分支,这可能是意外的。

但是,如果保证您的源表只包含部门12的项目,那么它将按您希望的那样工作。

在这种情况下,您还可以使用表表达式,例如CTE

WITH trg12
     AS (SELECT *
         FROM   trg
         WHERE  department = 12)
MERGE trg12 trg
using src
ON trg.student = src.student
WHEN matched THEN
  UPDATE SET name = src.name
WHEN NOT matched BY target THEN
  INSERT
  VALUES (12,
          src.student,
          src.name);
;