zoukankan      html  css  js  c++  java
  • TSQL--NULL值和三值逻辑

    在SQL SERVER 中逻辑表达式存在三种值:TRUE+FALSE+UNKNOWN。UNKNOW可以理解为不确定,既不是TRUE又不是FALSE的表达式,主要由与NULL相关的逻辑判断引起,值为NULL就意味着该未赋值或该值未确定。

    与NULL值做算术运算时,其结果是NULL,如果1+NULL结果为NULL

     

    SQL Server不同场景下对UNKNOWN处理不同,对NULL的处理也不同。

    1. 在WHERE+ON+HAVING三种筛选器中,所有运算结果非TURE(FALSE 与UNKNOW)的记录都不会返回;

    2. 在CHECK约束中,所有运算结果为非FALSE(TRUE与UNKNOW)的都属于满足CHECK约束的;

    3. 在UNIQUE约束中,如果列定义未限制为NOT NULL,那么允许该列存在一条NULL值,如果另外插入或更新一条记录为NULL时,会违法UNIQUE约束,NULL与NULL是相等的;

    4. 在GROUP BY中,NULL值被认为相同而分为一组,NULL与NULL是相等的;

    5. 在ORDER BY中,NULL值被认为相同而排列在一起,所有NULL值比已知值小,NULL与NULL是相等的;

     

    除上述3/4/5条中提到的情况外,NULL与NULL是不相等的。

    默认情况下,即SET ANSI_NULLS ON时,对于条件(WHERE C1 = NULL)这种查询,C1列值为NULL的行不会被返回;

    而当SET ANSI_NULLS ON时,对于条件(WHERE C1 = NULL)这种查询,C1列值为NULL的行会被返回,此时C1=NULL应该被理解为做C1 IS NULL 运算,而不应该理解为NULL与NULL相等;

    理解混乱的同学可以做以下测试:

     

    --==========================================
    --生成测试数据
    DECLARE @TB TABLE
    (
        C1 INT
    )
    
    INSERT INTO @TB
    SELECT 1
    UNION
    SELECT NULL
    
    --===========================================
    --修改默认选项值,设置ANSI_NULLS
    --注意该设置是回话级别,而不是批处理级别或语句级别
    SET ANSI_NULLS OFF;
    
    --============================================
    --当ANSI_NULLS OFF时,C1=NULL 等同于C1 IS NULL
    --因此查询返回一条NULL的记录
    SELECT * FROM @TB
    WHERE C1=NULL
    
    --============================================
    --当ANSI_NULLS OFF,NULL与NULL仍不认为相等
    --因此查询中不会返回NULL的记录
    SELECT * FROM @TB AS TB1
    INNER JOIN @TB TB2
    ON TB1.C1=TB2.C1

    运行结果为:

    为规范操作和避免混乱,强烈建议使用IS NULL 和IS NOT NULL判断值是否为NULL,避免修改默认选项ANSI_NULLS为OFF。

     

    除上面提到的特殊情况外,由于NULL与NULL是不相等的,因此

    1. 在做IN和EXISTS运算如WHERE C1 IN(SELECT ID FROM TB1) 或者 WHERE EXISTS (SELECT ID FROM TB1 WHERE ID =C1)时,所有C1列为NULL的行都不会被返回,无论表TB1的ID列是否存在NULL值;

    2. 对NOT IN运算如T1.C1 NOT IN (SELECT T2.C1 FROM T2) 时,如果表T2的C1列存在NULL值, 那么查询将不会返回任何记录,无论表T1的C1列是否有NULL值存在。

    3. 对NOT EXISTS运算如NOT EXISTS(SELECT C1 FROM T2 WHERE T2.C1=T1.C1),会返回T1表有但T2表没有且T1.C2 IS NOT NULL的记录

    测试DEMO

    --=================
    --生成测试数据
    DECLARE @TB TABLE
    (
        C1 INT
    )
    
    DECLARE @TB2 TABLE
    (
        C1 INT
    )
    
    
    INSERT INTO @TB
    SELECT 1
    UNION
    SELECT 2
    
    
    INSERT INTO @TB2
    SELECT 1
    UNION
    SELECT NULL
    
    --=================================
    --NOT EXISTS返回记录为2的行
    SELECT * FROM @TB AS TB1
    WHERE NOT EXISTS(
        SELECT C1 FROM @TB2 AS TB2 
        WHERE TB2.C1=TB1.C1)
    --================================
    --NOT IN 不返回任何行
    SELECT * FROM @TB
    WHERE C1 NOT IN
    (
        SELECT C1 FROM @TB2
    )
    View Code

     

    因此,IN和EXIST可以相互改写,但是NOT IN不能随便改写为NOT EXISTS.

     

    PS: 对于运算结果为UNKNOW的逻辑表达式,再做NOT运算,结果仍未UNKNOW

     --==========================================================

    妹子振贴

  • 相关阅读:
    python 查看安装包列表
    Centos7 linux下通过源码安装redis以及使用
    python 安装pip
    python3.7.2 pip 出现locations that require TLS/SSL异常处理方法
    Xshell报错“The remote SSH server rejected X11 forwarding request.”
    ERROR: child process failed, exited with error number 100
    centos7 (ifconfig不能使用) -bash: ifconfig: command not found
    gzip: stdin: not in gzip format tar: Child returned status 1 tar: Error is not recoverable: exiting now
    Centos7 安装python3.7.2
    Python安装常见问题:zipimport.ZipImportError: can't decompress data; zlib not available 解决办法
  • 原文地址:https://www.cnblogs.com/TeyGao/p/3519557.html
Copyright © 2011-2022 走看看