zoukankan      html  css  js  c++  java
  • 【原创】关于not in的一些事情

    早上到公司,收到一条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的使用场景和区别,见另一篇帖子:

  • 相关阅读:
    你笑的时候真的很美
    我不会倒下
    创业靠的是“脑子”,教你如何运用谋略事半功倍~
    其实我真的很在乎你
    让你克服低效率的困扰:从实质上迅速提升你生活的方法
    沈科(帮别人名字作诗)
    Secrets of the NetBeans Window System
    PropertyUtils.copyProperties的性能
    Swing Threading的限制
    SwingSet2
  • 原文地址:https://www.cnblogs.com/zhangxsh/p/3494414.html
Copyright © 2011-2022 走看看