• SQL避坑:当in,not in遇上null这种坑你避过吗?


    目录

    0 数据准备

    1 分析

    案例1:当过滤条件中in里面包含null

    案例2:当主表中有null,采用not in且not in后面不为子查询的时候会忽略NULL,匹配不到NULL,即查询不到任何NULL的记录

    案例3:当not in中包含NULL

     案例4:如果not in后面跟子查询时,所选的字段包含NULL值要特别注意

    2 小结

    0 数据准备

    1. create table t as
    2. select '张三' as name,1 as class
    3. union all
    4. select '李四' as name,1 as class
    5. union all
    6. select '王五' as name,2 as class
    7. union all
    8. select '老六' as name,null as class
    9. union all
    10. select '陈七' as name, 4 as class
    11. union all
    12. select '赵八' as name, 5 as class
    13. union all
    14. select '孙九' as name, 5 as class

    1 分析

    原表数据如下:

    案例1:当过滤条件中in里面包含null

    select * from t where class in (null,'1')

    in相当于or,对于null值得判断不是is null而是等于,因而对于NULL值得判断永远都是false

    select * from t where class ='1' or class =null

     

    如果想得到NULL的结果,一定要对NULL的值做转换,可以采用如下SQL

    select * from t where coalesce(class,'null') in ('null','1')

     

    结论:当in中包含 null,不会获取NULL的结果

    案例2:当主表中有null,采用not in且not in后面不为子查询的时候会忽略NULL,匹配不到NULL,即查询不到任何NULL的记录

    select * from t where class not in ('1','2')

    案例3:当not in中包含NULL

    select * from t where class not in ('1','2',null)


    not in 相当于and条件,只要有一个false,那么所有的都为false我们知道in not in都是用等号(=)来判断的,对于null不会使用is not null那么上面改写为:

    select * from t where class !='1'and !='2'and !=null

    结果如下:


    由于判读不等于NULL永远为false,所有整个条件判断都为false,where中为flase
    那么结果将什么也不会返回对于 要过滤null的情况,可以这样改写,将null转换为字符串'null',SQL如下:

    select * from t where coalesce(class,'null') not in ('1','2','null'

     案例4:如果not in后面跟子查询时,所选的字段包含NULL值要特别注意

    如下SQL:

    1. select *
    2. from t
    3. where class not in (
    4. select class
    5. from t t1
    6. where coalesce(t1.class, 'null') in (1, 2, 'null'))

     最终返回结果为空,原因是子查询中包含了NULL值,对于这种情况一定要特别注意,当not in中包含子查询时,如果结果中包含NULL值,将查不到任何结果,此时应该需要主动在子查询中将NULL值过滤掉。

    1. create table t1 as
    2. select 1 as class
    3. union all
    4. select 2 as class
    5. union all
    6. select 3 as class
    7. union all
    8. select 4 as class
    9. union all
    10. select null as class
    11. union all
    12. select null as class
    13. select *
    14. from t
    15. where class not in (
    16. select class
    17. from t1
    18. )

    最终结果为空

     正确的写法如下:

    1. select *
    2. from t
    3. where class not in (
    4. select class
    5. from t1
    6. where class is not null
    7. )

    此处有个问题,我们子查询中的接入如下:

    1. select class
    2. from t1
    3. where class is not null

    那么上述的结果与如下SQL等价吗?

    select * from t where class not in (1,2,3,4)

     执行上述SQL:我们得到的结果如下

     显然两个SQL不等价,也就是说当not in 中有子查询的时候,主表中的NULL不会忽略,可以得到主表NULL的结果,当not in中是常量值得时候,主表中的NULL被忽略,这个略有点坑。

    如果非要过滤掉NULL值,可以按如下写法 

    1. select *
    2. from t
    3. where coalesce(class,'null') not in (
    4. select coalesce(class,'null')
    5. from t1
    6. )

    2 小结

    • (1) 当in中过滤条件中存在NULL,无论in后面跟常量还是子查询主表中的NULL不会被过滤,此时需要 过滤可以用COALESCE()函数将NULL值转换
    • (2) 当主表中存在NULL,采用not in的时候,如果not in后面跟常量,筛选的结果中不会存在NULL,  就是会忽略NULL值,如果not in后面跟子查询,筛选的结果中会存在NULL值,很神奇,如果需要 NULL存在,则进行转换
    • (3) 当not in中包含NULL值,无论后面跟常量还是子查询,将不会有任何结果返回,这点一定要注意, 特别为子查询的时候需要根据业务需求将NULL进行转换或过滤NULL值

    总之用in的时候一般问题不大,使用not in的时候需要特别主要,结合本文恰当使用,之所以
    造成如此大的差异原因是对NULL的判断上,NULL的判断本质上is null或is not null,in或
    not in的判断是等于(=),所以对NULL判断是无效的,需要谨记。

  • 相关阅读:
    2022 CSP 游记
    基于JAVA航帆学院网站计算机毕业设计源码+数据库+lw文档+系统+部署
    交换--STP协议
    1.UEFI环境搭建
    关于CLR GC调优的一些问题
    c++ || 二分查找
    计算机毕业设计选题推荐-课程教学平台-Java/Python项目实战
    目标检测YOLO算法,先从yolov1开始
    攻破《数组与指针》相关笔试题(一)
    修炼k8s+flink+hdfs+dlink(六:学习k8s-pod)
  • 原文地址:https://blog.csdn.net/godlovedaniel/article/details/125376244