Merge:解析on子句和when not match子句的陷阱
在细节上,体现编程的修养。每一位大师,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 过滤条件。
Merge:解析on子句和when not match子句的陷阱的更多相关文章
- 1. 安装Oracle,配置环境 2. 实现查询From子句 3. 实现查询where子句 4. 实现查询order by子句
一.环境安装1. 登录:以管理员身份登录 sqlplus 登录名/密码 管理员身份登录:sqlplus system/1234562. 登录后,导入案例.下载scott.sql文件,执行下面一行的命令 ...
- 《读书报告 -- Elasticsearch入门 》--简单使用(2)
<读书报告 – Elasticsearch入门 > ' 第四章 分布式文件存储 这章的主要内容是理解数据如何在分布式系统中存储. 4.1 路由文档到分片 创建一个新文档时,它是如何确定应该 ...
- Neo4j使用Cypher查询图形数据
Neo4j使用Cypher查询图形数据,Cypher是描述性的图形查询语言,语法简单,功能强大,由于Neo4j在图形数据库家族中处于绝对领先的地位,拥有众多的用户基数,使得Cypher成为图形查询语言 ...
- Neo4j 第三篇:Cypher查询入门
本文转载自:https://www.cnblogs.com/ljhdo/p/5516793.html Neo4j使用Cypher查询图形数据,Cypher是描述性的图形查询语言,语法简单,功能强大,由 ...
- Cypher 语句实战
Cypher 语句实战 下载和安装 Neo4j windows 桌面版- 环境设置 https://www.w3cschool.cn/neo4j/neo4j_exe_environment_setup ...
- ElasticSearch 5学习(10)——结构化查询(包括新特性)
之前我们所有的查询都属于命令行查询,但是不利于复杂的查询,而且一般在项目开发中不使用命令行查询方式,只有在调试测试时使用简单命令行查询,但是,如果想要善用搜索,我们必须使用请求体查询(request ...
- ElasticSearch(6)-结构化查询
引用:ElasticSearch权威指南 一.请求体查询 请求体查询 简单查询语句(lite)是一种有效的命令行_adhoc_查询.但是,如果你想要善用搜索,你必须使用请求体查询(request bo ...
- ElasticSearch权威指南学习(结构化查询)
请求体查询 简单查询语句(lite)是一种有效的命令行adhoc查询.但是,如果你想要善用搜索,你必须使用请求体查询(request body search)API. 空查询 我们以最简单的 sear ...
- ES相关信息
漫画版原理介绍 搜索引擎的核心:倒排索引 elasticsearch 基于Lucene的,封装成一个restful的api,通过api就可进行操作(Lucene是一个apache开放源代码的全文检索引 ...
随机推荐
- docker in all
docker vs hyper-v,vmware,xen,kvm docker host, docker container, docker engineen, docker image images ...
- 【JAVA】使用 jedis操作redis——连接、存储数据、切库等
本篇运用Java调用jedis包(jedis在线文档API ),做简单操作实例. 安装jedis 1. 2.9.0 jar 版本下载: jedis-2.9.0.jar 2. 新建项目,添加该驱动包 连 ...
- Asp连接Oracle (包含绿色版12.2客户端和ODBC驱动安装)
我能操作的终端电脑是一台linux系统可以上互联网 ,服务器在部署在独立的私网上,不方便上互联网.服务器是2008R2.安装vs不是很方便.其所linux下作开发不是不可以,java php mono ...
- Android 增加JNI
Android:JNI 与 NDK到底是什么?(含实例教学) 前言 在android开发中,使用NDK开发的需求正逐渐增大: 很多人搞不懂JNI与NDK到底是怎么回事? 今天我们先介绍JNI与NDK之 ...
- jQuery插件实例五:手风琴效果[动画效果可配置版]
昨天写了个jQuery插件实例四:手风琴效果[无动画版]那个是没有动画效果的,且可配置性不高,本篇为有动画效果.对于一些数据做了动态的计算,以实现自适应. 欢迎大家入群相互交流,学习,新群初建,欢迎各 ...
- [部署]VM11下CentOS7mini安装及配置
最近使用了CentOS发现比Ubuntu更简洁,有些爱上CentOS了 1. 准备一版CentOS安装镜像文件 官网下载地址:http://www.centos.org/download/ 官方有三个 ...
- ethereumjs/ethereumjs-icap
https://github.com/ethereumjs/ethereumjs-icap ethereumjs-icap 安装: npm install ethereumjs-icap --save ...
- shiro实战系列(十二)之常用专业术语
请花 2 分钟来阅读和理解它——这很重要.真的.这里的术语和概念在文档的任何地方都被涉及到,它将在总体上 大大简化你对 Shiro 和安全的理解. 由于所使用的术语使得安全可能令人困惑.我们将通过 ...
- Android开发-各种各样好看漂亮的进度条,指示器,加载提示汇总
导读:之前项目中用到一些进度条,找了不少,打算写个demo自己总结一下,留着以后用, 有些是自己写的,有些是github上找的别人的库,如果大家觉得好看可以用,直接下载复制代码到项目里就可以用,ok ...
- Python中__init__()方法注意点
此文转自https://www.cnblogs.com/zyxstar2003/archive/2011/03/21/1989954.html 1.__init__并不相当于C#中的构造函数,执行它的 ...