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

运行结果为:

TSQL--NULL值和三值逻辑_第1张图片

为规范操作和避免混乱,强烈建议使用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

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

妹子振贴

TSQL--NULL值和三值逻辑_第2张图片

你可能感兴趣的:(TSQL--NULL值和三值逻辑)