TSQL Merge On子句和When not matched 语义理解
在细节上,体现编程的修养。每一位大师,master,其基础必定夯实。废话不多说,直接上干货,Merge子句用于对两个数据表执行数据同步,On子句指定匹配(when matched)条件,When子句指定额外的过滤条件和数据更新逻辑。源表(Source Table)和靶表(Targe Table)的数据行能够匹配成功,这意味着on子句和when match条件都被满足,进入到when matched子句定义的更新代码中,执行数据同步操作;如果不满足on子句,那么必须深入理解不匹配(when not matched)子句的条件,否则,很容易出错。首先查看MSDN对On子句的定义:
ON <merge_search_condition> Specifies the conditions on which source_table_ is joined with target_table to determine where they match.
也就是说,如果两个数据行满足on子句条件,那么数据处理程序跳转到when matched子句;如果两个数据行不满足on子句,那么数据处理程序跳转到when not matched子句。如果在on子句中只指定源表列和靶表列之间的匹配关系,那么同步操作一般不会出现“意外"的问题,意外是指符合设计者的预期。一旦在on子句中试图过滤靶表或源表的数据行,那么,再执行数据同步可能出现异常结果,出现不符合设计者预期的行为。实际上,MSDN已经明确给出提示,不要忽略这个提示,不然,你很可能已经挖了坑而不自知:
It is important to specify only the columns from the target table that are used for matching purposes. That is, specify columns from the target table that are compared to the corresponding column of the source table. Do not attempt to improve query performance by filtering out rows in the target table in the ON clause, such as by specifying AND NOT target_table.column_x = value. Doing so may return unexpected and incorrect results.
在开始测试when not matched子句的陷进之前,使用以下脚本创建示例数据:
create table dbo.dt_source
(
ID int,
Code int
)
go
create table dbo.dt_target
(
ID int,
Code int
)
go
insert into dbo.dt_source
(
ID,
Code
)
values(1,1),(2,1),(3,2),(4,2),(5,0)
GO
insert into dbo.dt_target
(
ID,
Code
)
values(1,1),(6,4)
GO
一,在on子句中过滤源表
1,在Merge的On子句中,使用额外的筛选条件(s.Code>0)对SourceTable进行过滤
对源表进行过滤,初衷是为了将SourceTable中Code>0的数据作为数据源同步到TargetTable,但是,在Merge命令的On子句中,s.Code>0只是一个匹配条件,用于when matched子句;然而,对于when not matched子句,是指不满足on条件:t.id=s.id and s.Code>0 ,这意味着when not matched匹配的查询条件是: t.id<>s.id or s.ID<=0,表达的逻辑是:s.id 和任意一个 t.id 都不相等, 或 s.ID<=0,这使得源表dbo.dt_source中Code<=0的数据行都满足when not matched子句的条件,被插入到dbo.dt_target中。
;merge dbo.dt_target as t
using dbo.dt_source as s
on t.id=s.id and s.Code>0
when matched
then update
set t.code=s.code
when not matched
then insert
(
ID,
Code
)
values
(
s.ID,
s.Code
);
查看TargetTable,Code=0的数据被插入到TargeTable表中,靶表的数据如下:

2,正确的写法:不要试图在on子句中过滤源表
在使用Merge命令同步数据时, 如果要过滤源表,正确的做法是把筛选条件放在所有的when子句中,包括When matched子句和when not matched子句。对on子句添加对源表的过滤条件,在when matched子句中,正常过滤源表,而在when not matched子句,会出现异常。
;merge dbo.dt_target as t
using dbo.dt_source as s
on t.id=s.id
when matched and s.Code>0
then update
set t.code=s.code
when not matched and s.Code>0
then insert
(
ID,
Code
)
values
(
s.ID,
s.Code
);
二,在on子句中过滤靶表(Target Table)
清空测试数据表,插入测试数据
insert into dbo.dt_source
(
ID,
Code
)
values(1,-1),(2,1),(3,2),(4,2),(5,0),(6,7)
GO
insert into dbo.dt_target
(
ID,
Code
)
values(1,1),(6,4)
GO
1,在on子句中对靶表进行过滤
在on子句中指定匹配条件:on t.id=s.id and t.Code<4,指定的时when matched的匹配条件,对于when not matched子句,匹配条件是:t.id<>s.id or t.Code>=4,对于源表数据行Row(6,7),不满足t.id<>s.id,因为存在TargetTableRow(6,4),但是满足 or 的另外一个条件 t.Code>=4, 所以,when not matched语句逻辑结果是true,执行insert语句。
;merge dbo.dt_target as t
using dbo.dt_source as s
on t.id=s.id and t.Code<4
when matched
then update
set t.code=s.code
when not matched
then insert
(
ID,
Code
)
values
(
s.ID,
s.Code
);
TargetTable的结果集如下图,包括(6,7)

2,分析陷进
这或许是你想要的结果,或许,你的本意是不希望 t.Code>=4的数据行插入到靶表中,如果merge子句要实现的业务逻辑是后者,那么数据同步将出现异常,所以一定要深刻理解when not matched子句的匹配条件,推荐的做法是:不要试图在on子句中过滤源表或靶表,如果必须要过滤数据行,那么请在每个when子句(when matched和when not matched)中,添加额外的and 过滤条件。
TSQL Merge On子句和When not matched 语义理解的更多相关文章
- TSQL Merge 用法
在更新数据仓库时,经常需要根据源表对Target表进行数据同步,Merge 命令具有数据更新,删除,插入的功能,专门用于数据同步,并将数据的更新输出到表中.在使用Merge命令时,需要注意when n ...
- TSQL order by 子句中排序列的多种写法
Order by 子句用于对结果进行排序,执行顺序位于select子句之后,排序列有4中写法: column_name column_alias,由于order by子句的执行顺序位于select子句 ...
- T-SQL ORDER BY子句 排序方式
MS SQL Server ORDER BY子句用于根据一个或多个列以升序或降序对数据进行排序. 默认情况下,一些数据库排序查询结果按升序排列. 语法 以下是ORDER BY子句的基本语法. SELE ...
- T-SQL GROUP BY子句 分组查询
SQL Server GROUP BY子句与SELECT语句协作使用,以将相同的数据分组. GROUP BY子句位于SELECT语句中的WHERE子句之后,位于ORDER BY子句之前. 语法 以下是 ...
- T-SQL 重复读(Double Read)问题的理解
我的理解是: step1,假设表里有100行有序记录, 事务1从row 1 开始读取到了row 50 并准备继续读取完这100行. 要注意的是,sql server 会自动释放已经读取了的row的锁. ...
- Merge:解析on子句和when not match子句的陷阱
在细节上,体现编程的修养.每一位大师,master,其基础必定夯实.废话不多说,直接上干货,Merge子句用于对两个数据表执行数据同步,On子句指定匹配(when matched)条件,When子句指 ...
- T-SQL基础(五)之增删改
在前面的文章中对T-SQL的查询做了基本总结,接下来我们看下SQL中的另外一个常用操作——数据的修改. INSERT INSERT 向数据表中插入数据的基本语句,句式: INSERT INTO tab ...
- SQL Server2012 T-SQL基础教程--读书笔记(8 - 10章)
SQL Server2012 T-SQL基础教程--读书笔记(8 - 10章) 示例数据库:点我 CHAPTER 08 数据修改 8.1 插入数据 8.1.1 INSERT VALUES 语句 8.1 ...
- The use of function Merge (update、insert、delete)
1.The use of function merge(update.insert.delete) Example: #1.Initialize the data create table #test ...
随机推荐
- IOS UIAppLocation 单例模式
UIApplocation * app=[UIApplocation shareapplocation]; UIAppLocation 只能被初始化一次. 一个程序中只能被创建一次,称为单例模式. 单 ...
- 未能添加对***.dll的引用 问题解决方法
这个不是什么新问题了,这里说一下我遇到的这个操蛋事. 转载请注明出处 http://www.cnblogs.com/zaiyuzhong/p/6236263.html 我做的和往常一样,找到SDK开发 ...
- PHPer不能不看的50个细节!
1.用单引号代替双引号来包含字符串,这样做会更快一些.因为PHP会在双引号包围的字符串中搜寻变量, 单引号则不会,注意:只有echo能这么做,它是一种可以把多个字符串当作参数的"函数&quo ...
- linux菜鸟日记(3)
Centos7利用shell编辑一串 一键完成一些基础配置的代码: 在这串shell代码中我实现了 IP地址的配置.光盘的挂载.本地yum源的搭建.一些服务的安装例如 httpd. php. ntp ...
- Oracle Flashback 闪回
Oracle 的闪回技术是一种数据恢复技术,仅能对用户逻辑错误进行恢复, 闪回针对的是提交commit的事务,没有提交的事务,使用rollback 1.闪回版本查询 Flashback Version ...
- [转]Android Studio 里搭建自动化测试框架Robotium
Android的自动化测试框架可选择的不多,后来选了Robotium(https://code.google.com/p/robotium/),它的语法及易用性挺像我们用在iOS里的KIF. 官方文档 ...
- iOS 中 ARC 项目 兼容 MRC
iOS 项目中MRC 和 ARC 项目的代码兼容问题: 1.ARC 项目中导入 MRC 第三方类的时候要在此类上添加 -objc-arc. 2.MRC 项目中导入 ARC 类的时候要在次类上添加 -f ...
- JavaScript固定宽高
固定高宽: <script type="text/javascript"> if (/Android (\d+\.\d+)/.test(navigat ...
- tab+tab
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/ ...
- java并发编程(十五)内存可见两种方式 加锁和volatile
1.volatile变量是一种稍弱的同步机制在访问volatile变量时不会执行加锁操作,因此也就不会使执行线程阻塞,因此volatile变量是一种比synchronized关键字更轻量级的同步机制. ...