NULL表示unknown,不确定值,所以任何值(包括null值)和NULL值比较都是不可知的,在on子句,where子句,Merge或case的when子句中,任何值和null比较的结果都是false,这就是NULL设下的陷阱,我被坑过。

有一次,我使用Merge同步数据,由于target表中存在null值,虽然在source表中对null值做过处理,但是忽略了target表中的null值,导致数据merge失败。

step1,创建示例数据

--create source table
create table dbo.dt_source
(
id int null,
code int null
)
on [primary]
with(data_compression=page) --create target table
create table dbo.dt_target
(
id int null,
code int null
)
on [primary]
with(data_compression=page)

step2,插入示例数据

示例数据中,Source表和Target表中都存在null值,不管是在Source表,还是在Target表,都要避免和null值进行比较。

--insert data into table
insert into dbo.dt_source(id,code)
values(1,1),(2,2),(3,null) insert into dbo.dt_target(id,code)
values(1,1),(2,null)

step3,错误写法:只处理Source表中的null,而忽略Target表中的null

-- -1 stand for unknwon value
merge dbo.dt_target t
using dbo.dt_source s
on t.id=s.id
when matched and( t.code<>isnull(s.code,-1))
then update
set t.code=s.code
when not matched
then insert(id,code)
values(s.id,s.code);

查看Target和Srouce表中的数据,数据不同步,不同步的原因是when matched子句之后的and 条件, t.code中存在null值,null值和任何值(包括null值)比较的结果都是unknown,在when子句中视为false。

正确写法1,不管是在target表,还是在source表,只要存在null值,必须进行处理,避免出现和null进行比较的情况。

处理的方式是使用一个值来表示unknwon,如果ID列有效值不可能是负值,那么可以使用-1来代替unknown。因为-1和-1 是相等的,逻辑上就将null值和null值视为相同。

-- -1 stand for unknwon value
merge dbo.dt_target t
using dbo.dt_source s
on t.id=s.id
when matched and( isnull(t.code,-1)<>isnull(s.code,-1))
then update
set t.code=s.code
when not matched
then insert(id,code)
values(s.id,s.code);

正确写法2,在条件子句中,使用is null或 is not null来处理null值。

Tsql 使用is null和is not null来确实是,不是 null。 null is null 的逻辑值是true,other_value is null 为false, other_value is not null 为true。

merge dbo.dt_target t
using dbo.dt_source s
on t.id=s.id
when matched and( t.code<>s.code or t.code is null or s.code is null)
then update
set t.code=s.code
when not matched
then insert(id,code)
values(s.id,s.code);

NULL的陷阱:Merge的更多相关文章

  1. Merge语句中NULL的陷阱

    NULL表示unknown,不确定值,所以任何值(包括null值)和NULL值比较都是不可知的,在on子句,where子句,Merge或case的when子句中,任何值和null比较的结果都是fals ...

  2. Merge使用

    Role r = new Role(); r.setName("TEST"); r.setDescription("123"); r.setLevel(2); ...

  3. shell中while循环的陷阱

    在写while循环的时候,发现了一个问题,在while循环内部对变量赋值.定义变量.数组定义等等环境,在循环外面失效. 一个简单的测试脚本如下: #!/bin/bash echo "abc ...

  4. 关于 JavaScript 中 null 的一切

    原文地址:Everything about null in JavaScript 原文作者:Dmitri Pavlutin 译者:Gopal JavaScript 有两种类型:原始类型(strings ...

  5. [MySQL Reference Manual]15. 其他存储引擎

    15. 其他存储引擎 15. 其他存储引擎 15.1 设置存储引擎 15.2 MyISAM存储引擎 15.2.1 MyISAM启动选项 15.2.2 Key的空间要求 15.2.3 MyISAM表存储 ...

  6. javascript 手势缩放 旋转 拖动支持:hammer.js

    原文: https://cdn.rawgit.com/hammerjs/hammer.js/master/tests/manual/visual.html /*! Hammer.JS - v2.0.4 ...

  7. 【SQL】CLR聚合函数什么鬼

    之前写过一个合并字符串的CLR聚合函数,基本是照抄MS的示例,外加了一些处理,已经投入使用很长时间,没什么问题也就没怎么研究,近日想改造一下,遇到一些问题,遂捣鼓一番,有些心得,记录如下. 一.杂项 ...

  8. mm/mmap.c

    /* *    linux/mm/mmap.c * * Written by obz. */#include <linux/stat.h>#include <linux/sched. ...

  9. java Util

    import com.alibaba.fastjson.JSON; import com.alibaba.fastjson.JSONObject; import com.qihangedu.tms.a ...

随机推荐

  1. 树链剖分+线段树 HDOJ 4897 Little Devil I(小恶魔)

    题目链接 题意: 给定一棵树,每条边有黑白两种颜色,初始都是白色,现在有三种操作: 1 u v:u到v路径(最短)上的边都取成相反的颜色 2 u v:u到v路径上相邻的边都取成相反的颜色(相邻即仅有一 ...

  2. SOAPUI使用教程-REST功能测试

    当创造了SoapUI功能测试用例,常见的情况是,你调用一些REST资源和验证其响应检查返回正确的结果.这可以容易地实现: 添加一个REST请求到新的test step或现有的TestCase 添加断言 ...

  3. Linux内核笔记--网络子系统初探

    内核版本:linux-2.6.11 本文对Linux网络子系统的收发包的流程进行一个大致梳理,以流水账的形式记录从应用层write一个socket开始到这些数据被应用层read出来的这个过程中linu ...

  4. [转] nodemon 基本配置与使用

    在开发环境下,往往需要一个工具来自动重启项目工程,之前接触过 python 的 supervisor,现在写 node 的时候发现 supervisior 在很多地方都有他的身影,node 也有一个 ...

  5. js中substr,substring,indexOf,lastIndexOf的用法小结

    第一组:str.substr(start,length) 和 str.substring(start,end) 定义: str.substr(start,length) substr(start,le ...

  6. Android开发学习路线图

    Android开发学习方法: Android是一个比较庞大的体系,从底层的Linux内核到上层的应用层,各部分的内容跨度也比较大.因此,一个好的学习方法对我们学习Android开发很重要. 在此建议, ...

  7. 20155315庄艺霖--对做中学的理解及对c语言和Java的看法

    关于做中学的理解及技能训练的思考 在写这篇博客之前,我首先阅读了娄老师的博客,对做中学的概念很感兴趣.我们常说知识要学以致用,做中学强调的是在用的过程中有新的收获和体会来进一步巩固学习.细数我学过的课 ...

  8. 2015-12-21(box-sizing:border-box)

    最近新学了一个方法box-sizing:border-box,可以忽略margin,padding,border等所要占的位置,比如,你在做响应式网页时,当你所做的网页宽度是符合当前电脑屏幕宽度时,但 ...

  9. Python之路第一课Day6--随堂笔记(面向对象 )

    本节内容: 1. 面向对象编程介绍 2. 为什么要用面向对象进行开发? 3. 面向对象的特性:封装.继承.多态 4. 类.方法   一.面向过程 VS 面向对象  1. 编程范式 编程是 程序 员 用 ...

  10. Struts 2的拦截器(Interceptor)总结

     什么是Struts 2拦截器? 从软件构架上来说,拦截器是实现了面向方面编程的组件.它将影响了多个业务对象的公共行为封装到一个个可重用的模块,减少了系统的重复代码,实现功能的高度内聚,确保了业务对象 ...