早上到公司,收到一条cocall消息,是某哥们遇到的疑惑,可能很多新手并不知情:

请教个问题
我执行
1. select * from t_htgl_htpswj t where t.c_wjmc = '山西'; 结果是 存在一条记录
2. select * from t_htgl_fj t where t.c_wjmc = '山西'; 结果是不存在记录
3. 为什么执行
select count(*) from t_htgl_htpswj htpswj where htpswj.c_wjmc not in (select fj.c_wjmc from t_htgl_fj fj )
按照 1,2的执行结果,3的结果应该是至少是1才对呀,为什么实际执行结果是0呢。。。。 C_WJMC的类型都是VARCHAR(200)
很诡异的是 第三个查询,我如果用下面这个语句统计查询又是可以查询到结果的。。。。
select count(*) from t_htgl_htpswj htpswj where htpswj.c_wjmc not in (select fj.c_wjmc from t_htgl_fj fj where fj.n_xsxm_htps is not null)
我添加的这个子查询的条件好像和整体查询没有关系呀。。。

对于这个问题,需要了解以下两点内容:
1.null到底是个什么东西?
2.not in是如何执行的,什么原理?
下面看第一点:
1.null到底是个什么东西?我们知道在存储过程中:select a into b from t1 where c='';--如果返回的记录为零,那么会报错,此时实际上返回的就是一个null,一般在前面加一个count的判断再into。
null在oracle中代表什么都不是,空记录,这个地球人都知道,关键是在运算中,null和任何值的算术或者逻辑运算结果都是null,而且它和任何值都不相等,也非不相等,和自身也不相等,如:
select * from t1 where a=null;--查不到正确的记录
select * from t1 where null=null;--查不到记录。因此在判断空与非空时使用is null或者is not null来判断,以下是有个哥们让优化的sql:

..........
union all
select C_BH,N_AJLB,C_AH,C_AJJC,C_AJMC,C_BH_SAR,D_BJRQ,C_BH_CBDW from t_ywgy_hztj_aj where n_ajlb = 202 and C_TBLX <> null union all
select C_BH,N_AJLB,C_AH,C_AJJC,C_AJMC,C_BH_SAR,D_BJRQ,C_BH_CBDW from t_ywgy_hztj_aj where n_ajlb = 302 and C_TBLX <> null ...........

这样写是不对的,会获取不到正确的记录。应该这样写:
select * from t1 where a is null or b is not null;

插播一点,is null和is not null判断都是无法使用索引的,tom的书上有个很不错的提议,就是将null以一个值来代替,如果某列代码值为空,如不妨以-1来代表null,字符的话也可以以其他值(如‘null’)代替,这样在判断的时候可以使用索引。
2.not in 是如何执行的?
先看in是如何执行的:
如:

select * from t where a in(1,2,3);查询等价于:
select * from t where a=1 or a=2 or a=3;

如果条件有null呢?

select * from t where a in(1,2,3,null);等价于:
select * from t where a=1 or a=2 or a=3 or a=null;
--这是没有问题的,一般一样可以得到正确结果,因为a和null不相等,因此null值会被忽略

那么not in呢?

select * from t where a not in(1,2,3);--等价于
select * from t where a !=1 and a!=2 and a!=3;

如果这个条件中有null值呢?

select * from t where a not in(1,2,3,null);--等价于
select * from t where a !=1 and a!=2 and a!=3 and a!=null;

看a!=null,这个条件是不成立的,始终都是false,所以导致整个表达式为false,所以查不到任何记录。

回到开头的问题:

select  count(*) from t_htgl_htpswj htpswj where htpswj.c_wjmc not in (select fj.c_wjmc from t_htgl_fj fj  );

"select fj.c_wjmc from t_htgl_fj fj",这个sql中c_wjmc返回的结果是否包含null值呢?
我们执行以下sql:
select count(*) from t_htgl_fj fj where fj.c_wjmc is null;
----------
COUNT(*)
30
----------
所以,子查询中的c_wjmc存在null值,导致整个where的逻辑运算结果为false,因此没有返回任何结果。
那么为什么

“select count(*) from t_htgl_htpswj htpswj where htpswj.c_wjmc not in (select fj.c_wjmc from t_htgl_fj fj where fj.n_xsxm_htps is not null)”查询就能返回结果呢?

select fj.c_wjmc from t_htgl_fj fj where fj.n_xsxm_htps is not null;--这个查询中c_wjmc有没有空值呢?
执行以下查询:

select count(*) from thims.t_htgl_fj fj where fj.n_xsxm_htps is not null and c_wjmc is null;--n_xsxm_htps为空且c_wjmc也为空的记录:
----------
COUNT(*)
0
----------

这个查询中恰巧n_xsxm_htps is not null将所有的c_wjmc为null的记录过滤掉了,所以子查询中没有null值,所以能查到正确的结果。

结论:在not in的查询中,如果子查询结果中包含null值,将查不到记录,not in无法处理null值。因此可以使用exists,如果非要使用not in,也要保证在子查询中将null值过滤掉。
通常情况下,exists效率要高于in,而且exists可以准确的处理null值(其实是事先过滤掉罢了,不再赘述),关于exists和in的使用场景和区别,见另一篇帖子:

【原创】关于not in的一些事情的更多相关文章

  1. LM-MLC 一种基于完型填空的多标签分类算法

    LM-MLC 一种基于完型填空的多标签分类算法 1 前言 本文主要介绍本人在全球人工智能技术创新大赛[赛道一]设计的一种基于完型填空(模板)的多标签分类算法:LM-MLC,该算法拟合能力很强能感知标签 ...

  2. Django admin美化插件suit应用[原创]

    前言 由于比较懒,自己弄了一个用户验证,没有自己写后台,用了django自带的user认证,并通过admin直接进行管理,但默认的admin并不漂亮,于是使用了这个django-suit插件,效果对比 ...

  3. 【原创】自己动手写工具----XSmartNote [Beta 3.0]

    一.前面的话 在动笔之前,一直很纠结到底要不要继续完成这个工具,因为上次给它码代码还是一年多之前的事情,参考自己动手写工具----XSmartNote [Beta 2.0],这篇博文里,很多园友提出了 ...

  4. 【原创】自己动手写工具----签到器[Beta 2.0]

    一.前面的话 上一篇中基本实现了简单的签到任务,但是不够灵活.在上一篇自己动手写工具----签到器的结尾中,我设想了几个新增功能来提高工具的灵活程度,下面把新增功能点列出来看看: (1)新增其他的进程 ...

  5. 【原创】轻量级移动设备即时通讯技术MobileIMSDK的常见问题解答

    申明:MobileIMSDK 目前为个人原创开源工程且已发布,现整理了一些有关MobileIMSDK的常见的问题,希望对需要的人有用,谢谢.如需与作者交流,见文章底部个人签名处,互相学习. Mobil ...

  6. [原创]cocos2d-x研习录-第三阶 特性之物理引擎

    游戏物理引擎是指在游戏中涉及物理现象的逻辑处理,它用于模拟现实世界的各种物理规律(如赛车碰撞.子弹飞行.物体掉落等),让玩家能够在游戏中有真实的体验. Cocos2D-x中支持Box2D和Chipmu ...

  7. 【原创】loadrunner12.53 录制脚本时 打不开网页或者打开网页慢?

          问题描述: 之前刚装12.5版本时候,用 WebTours测试过,应用程序选择自己本地IE浏览器.exe程序,输入url地址就可以成功录制了 . 但是由于公司网络配置环境改变了(猜测),现 ...

  8. 玩转CSS3,嗨翻WEB前端,CSS3伪类元素详解/深入浅出[原创][5+3时代]

    在我的上一篇博客中, 很多园友提出说对css3"画图"不是很理解, 在跟他们私聊了一段时间以后,加上自己在开始自学css3的时候的疑惑,我觉得大家之所以不是很理解主要是因为对伪元素 ...

  9. html5+css3实现跑动的爱心/动态水滴效果[原创][5+3时代]

    大风起兮云飞扬,安得猛士兮走四方!html5+css3,不学不行. 做web开发已经有好几年了,见证了太多语言的崛起和陨落. 其实作为一个程序员最苦逼的事情莫过于每天要不停的追赶各大公司新出的框架和语 ...

随机推荐

  1. Controller总结

    下图显示了组建之间的基本控制流程 1.1控制器工厂.动作调用器 控制器工厂负责创建对请求进行服务的控制器实例 动作调用其负责查找并调用控制器类中的动作方法. 1.2自定义控制器工厂 namespace ...

  2. Java基础——StringBuffer和StringBuilder

    本节讲述2个字符串容器的区别 StringBuffer和StringBuilder区别: 1.相同点 两者都是容器(可变的字符序列),都可以对字符串进行基本的“增删改查”操作. 2.不同点 Strin ...

  3. iOS开发者账号证书配置及相关工作

    申请到开发者账号,肯定要先配置一下才可以使用,这主要是iOS证书及配置文件: 以下这篇文章写得比较全面,故不再累赘,需要的同学可以看一下: iOS开发证书与配置文件的使用

  4. 使用LayUI在页面实现加载层(图标)代码:

    实现代码: var index = layer.load({ shade: [0.4,'#def'], icon :' 实现效果: 可以使用 layer.close(index); 来控制其在什么时 ...

  5. Codeforces Round #470 (rated, Div. 2, based on VK Cup 2018 Round 1)B. Primal Sport

    Alice and Bob begin their day with a quick game. They first choose a starting number X0 ≥ 3 and try ...

  6. ARM - Linux嵌入式C/C++各种资料分享【更新日期:2012/04/24】

    http://blog.csdn.net/shuxiao9058/article/details/6786868 由于115网盘取消大众分享功能,因此不能继续分享下载链接.更新资料将在本人分享空间转存 ...

  7. 小学生绞尽脑汁也学不会的python(面对对象-----成员)

    小学生绞尽脑汁也学不会的python(面对对象-----成员) 成员 class Person: def __init__(self, name, num, gender, birthday): # ...

  8. 倍增算法总结 ( 含RMQ模板)

    部分题目来自<算法竞赛设计进阶> 问题       给定一个长度为n的数列A,有m个询问,每次给定一个整数T,求出最大的k,满足a[1],a[2]……a[k]的和小于等于T(不会打sigm ...

  9. Visual Studio 2015 改变窗体图标 & 任意位置打开窗体 & 禁止鼠标改动窗体大小

    1.改变窗体图标 先把图标放到项目文件夹中,然后点击窗体属性的ICON添加即可. 参考:https://www.cnblogs.com/yangxuli/p/8075484.html?tdsource ...

  10. js数字转换为float,取N个小数

    javascript中的变量都是弱类型,所有的变量都声明为var,在类型转换过程中就没有java那么方便,它是通过 parseInt(变量).parseFloat(变量)等方法来进行类型转换的.注意: ...