关于MS sql的MERGE 语法原理

0
各位大神现在我有一个问题被困扰了,就是关于MERGE的原理问题,我之前的理解是 目标表和源表 用ON后面的条件进行inner join 的关联,存在的话即进行关联,不存在的话进行插入.但是现在我发现 我这样理解貌似不对,所以请各位大神帮我重新解答一下原理.
下面是我的测试代码
CREATE TABLE test1 (NAME NVARCHAR(10),ID INT,CODE NVARCHAR(10) );
INSERT INTO test1 VALUES  ('冰魂哥布林',1,'A'),('火舞哥布林',2,'A'),('闪刃哥布林',1,'B')
CREATE TABLE test2 (NAME NVARCHAR(10),ID INT,CODE NVARCHAR(10),ISNEW INT  );
TRUNCATE TABLE test2
--测试1
MERGE test2 AS T USING test1 AS S
ON T.CODE=S.CODE AND S.ID=1
WHEN MATCHED THEN UPDATE SET NAME=S.NAME,id=s.id
WHEN NOT MATCHED THEN INSERT (NAME ,id ,code) VALUES (S.NAME ,S.id ,S.code);
SELECT * FROM test2;
--测试二
TRUNCATE TABLE test2

MERGE test2 AS T USING (SELECT * FROM  test1 WHERE ID=1) AS S
ON T.CODE=S.CODE 
WHEN MATCHED THEN UPDATE SET NAME=S.NAME,id=s.id
WHEN NOT MATCHED THEN INSERT (NAME ,id ,code) VALUES (S.NAME ,S.id ,S.code);
再我之前的理解中 ,测试一和测试二的结果应该是一样的啊,但是却不一样.如下图
测试一.png

测试二.png

 
然后 还一个问题
MERGE test2 AS T USING test1 AS S
ON T.CODE=S.CODE AND T.ISNEW=1
WHEN MATCHED THEN UPDATE SET NAME=S.NAME,id=s.id
WHEN NOT MATCHED THEN INSERT (NAME ,id ,code) VALUES (S.NAME ,S.id ,S.code);
上面代码中的T.ISnew=1和测试一种的S.ID=1的限制原理不一样么.
忘各位大神解除我的疑惑,谢谢
 
已邀请:
0

Bob - 同程旅游大数据+BI 架构师 2015-10-21 回答

针对测试一和测试二的结果,我的理解如下,仅供参考。
测试一的场景是:
1.取出全部的test1表数据,按照 T.CODE=S.CODE AND S.ID=1 这个条件来做判断:
如果满足这个条件则执行更新或新增。
test1表中ID= 1的有两条记录,但是code不相等,所以执行的是新增
test1表中有一条记录不满足 T.CODE=S.CODE AND S.ID=1 这个条件,执行的也是新增
因此,目标表中总计有三条。
 
测试二的场景是:
1.只取test1表中ID=1的记录数,按照 T.CODE=S.CODE 这个条件来做判断:
满足条件则更新,不满足则新增
 
所以这两个测试的结果是不一样的。
 
 
最后一个问题:
由于你的test2表中没有任何记录,所以你的 ON T.CODE=S.CODE AND T.ISNEW=1 和 T.CODE=S.CODE AND S.ID=1 这两个语句执行结果是一致的。
但是当test2表中有数据,且isnew不为null时,结果可能就不一样了。
 
这两个判断条件是完全不一样,和原理没啥关系。
 
0

- 取是能力,舍是境界 2015-10-21 回答

你对Merge语法的理解是没有问题的。根据目标表和源表根据on条件,能够匹配则执行WHEN MATCHED THEN部分,不能匹配则执行WHEN NOT MATCHED操作,如果在源表不存在想删除,可以when not matched by source then delete。
 
测试1和测试2为什么结果不同。
测试1,你虽然有S.ID = 1 但是忽略了另一个条件T.CODE=S.CODE,由于表test2是空的,所以这儿on条件一直是false,所以执行了三次插入。
测试2,你源表本身做了过滤,则源表只剩下2条记录。同测试1一样,你的条件T.CODE=S.CODE,一直是False,所以执行了二次插入。
 
至于最后你提到问题和测试1是一样的情况。S.IsNEW条件根本没有起作用。
0

gogodiy - 天善智能数据库专家、Tableau爱好者 2015-10-21 回答

方法1,你使用的是test1表的全部记录(3条),此时text2表无记录,那么不论ON后面是什么条件,都只会执行INSERT语句,因此添加到text2表的记录是3条。
方法2,你使用的是(select * from test1 where id=1),因此记录数只有2条,此时text2表无记录,那么不论ON后面是什么条件,都只会执行INSERT语句,因此添加到text2表的记录也是2条。
方法1和方法2的根本区别在于你test1表参与的数据量的多少。换句话说,是先执行USING,确定参与MERGE的test1表的记录数,然后再执行ON进行关联判断。
建议看下T-SQL代码的执行顺序,就容易理解了。

要回复问题请先登录注册