SQL Server 2012 中不同的子句如何处理 Null/Unknow?

new*_*int 2 null sql-server

(SQL 和 SQL Server 相对较新)我正在阅读Itzik Ben-Gan 的SQL Server 2012 T-SQL Fundamentals。奥托尔指出:

SQL 在不同的语言元素中对 UNKNOWN 有不同的处理方式

所以,我浏览了 SQL Server 文档,特别是WHEREclause,但找不到任何关于如何NULL/UNKNOWN处理的具体信息。

有人可以指出我正确的文档或指出我在文档中读错的内容吗?(我高度怀疑我的问题的答案深藏在 SQL 标准的某个地方,但对我来说可能太复杂了,至少在这一点上。)

ype*_*eᵀᴹ 8

在不同条款中如何处理UNKNOWNNULL处理这些条款存在细微差别。

可以出现布尔表达式的三个子句是WHERE,HAVINGFROM(在ON子子句中)。在所有三个中,UNKNOWN都以相同的方式处理。

  • WHERE <boolean expression>

    <boolean expression>如果表达式的计算结果为 ,则一行“通过”并返回TRUE。如果表达式的计算结果为FALSEor UNKNOWN,则该行不会通过并从查询的进一步计算中删除。

  • HAVING <boolean expression>

    HAVING子句中检查的行是由前一个GROUP BY子句的聚合创建的行。类似于上面的一行(由聚合创建)“传递”<boolean expression>并且如果表达式的计算结果为 则返回TRUE。如果表达式的计算结果为FALSEor UNKNOWN,则该行不会通过并从查询的进一步计算中删除。

  • a JOIN b ON <boolean expression>

    from 的每一行都根据 的每一行进行a检查b。如果表达式为TRUE,则检查通过并且两行的组合对于查询的进一步处理有效。如果FALSEUNKNOWN,则拒绝组合。
    当联接是外联接(LEFT,RIGHTFULL)时,会略有变化,但与如何UNKNOWN处理无关。这里发生的情况是,如果左表中的一行(在LEFT连接中)与右表中的任何行都不匹配(即其所有检查的计算结果为FALSEUNKNOWN),则该行仍被转发,并且b列的缺失值填充空值。)

约束的情况不同,对于UNKNOWN. 我想这与首先允许空值的决定有关。空值将导致UNKNOWN大多数约束的结果,因此允许插入这些行是有意义的。否则,效果将与将列声明为NOT NULL.

  • CHECK 约束: CHECK <expression>

    如果表达式的计算结果为TRUE ,则允许插入(或更新)一行UNKNOWN。仅当表达式的计算结果为 时才会被拒绝FALSE

  • FOREIGN KEY 约束,具有可为空的列。

    与检查约束类似,如果某行在参与外键约束的列之一中为空,FOREIGN KEY则跳过该约束的验证并允许插入(或更新)该行。可以想到一个表中的外键约束a

    FOREIGN KEY (column) REFERENCES b (column)
    
    Run Code Online (Sandbox Code Playgroud)

    相当于:

    CHECK (column IN (SELECT column IN b))
    
    Run Code Online (Sandbox Code Playgroud)

    因此,如果a.columnis NULL,则表达式被计算为UNKNOWN,因此该行是允许的。

  • UNIQUE 约束

    这里 SQL-Server 偏离了标准,即如果具有唯一约束的行包含NULL,则跳过唯一检查并允许该行。
    SQL-Server 将空值视为常规值,当涉及到唯一约束时,此类列中NULL允许一个


NULL 值在某些子句中也有特殊处理:

  • GROUP BY

    如果分组列包含空值,则所有空值都被视为相等,并将它们放入一个组中(同样的事情发生在SELECT DISTINCT查询中。)

    聚合函数(MIN()MAX()SUM()AVG()等)不具备与例外的零点COUNT(),可以做很多不同的事情:

    • COUNT(*)COUNT(constant)会计算所有行。
    • COUNT(column)并且COUNT(expression)会像其他聚合函数一样忽略空值,并且只计算列或表达式不为空的行。
    • COUNT(DISTINCT column)并且COUNT(DISTINCT expression)还将忽略空值并仅计算不同的非空列或表达式。

    因此,如果列中有空值,以下 4 个查询可能会返回 4 个不同的结果:

       SELECT COUNT(*) FROM t ;
       SELECT COUNT(c) FROM t ;
       SELECT COUNT(DISTINCT c) FROM t ;
       SELECT COUNT(*) FROM (SELECT DISTINCT c FROM t) AS x ;
    
    Run Code Online (Sandbox Code Playgroud)
  • ORDER BY

    • 在它们之间的比较中,NULL值被视为相等。
    • 将它们与非空值进行比较时,空值被视为可能的最低值,低于任何非空值。因此,它们在订单为ASC时最先出现,在订单为 时最后出现DESC
      (最新标准中定义了NULLS LASTandNULLS FIRST属性,但 SQL Server 尚未实现。)