【问题标题】:Why does SQL Server 2005 think COUNT(...) is nullable?为什么 SQL Server 2005 认为 COUNT(...) 可以为空?
【发布时间】:2017-09-11 18:31:59
【问题描述】:

当我这样做时

CREATE VIEW Test1 AS
WITH OneRow AS (SELECT a = 1)
SELECT countt = COUNT(*)
FROM OneRow

GO

SELECT COLUMN_NAME, IS_NULLABLE FROM INFORMATION_SCHEMA.COLUMNS WHERE TABLE_NAME = 'Test1'

我明白了

COLUMN_NAME IS_NULLABLE
----------- -----------
     countt         YES

我本来希望IS_NULLABLENO,因为我认为COUNT(*) 总是返回一个数字。

在哪些情况下COUNT(*) 可以返回NULL?把它包装成ISNULL(COUNT(*), 0) 有什么危险吗?有必要这样做似乎很奇怪。确实,在任何情况下COUNT(anything) 可以返回NULL

【问题讨论】:

    标签: sql-server sql-server-2005


    【解决方案1】:

    我认为您的具体情况不会在该计算列中看到 NULL,而且我认为将列包装在 ISNULL() 中没有问题。 SQL Server 通常将计算列报告为 NULLABLE。

    来自https://technet.microsoft.com/en-US/library/ms191250.aspx

    数据库引擎自动确定可空性 根据使用的表达式计算列。大多数的结果 即使只有不可为空的列,表达式也被认为可以为空 存在,因为可能会产生下溢或上溢 空结果也是如此。将 COLUMNPROPERTY 函数与 AllowsNull 属性来调查任何计算的可空性 表中的列。可以为空的表达式可以转换为 通过指定 ISNULL(check_expression, constant) 的不可为空的一个, 其中常量是一个非空值,替换为任何空结果。

    【讨论】:

    • 如果你引用了一些东西,请使用> 正确引用它(或块引用按钮)。否则您将被标记为侵犯版权。
    • 换句话说,该列在技术上可以为空,但它绝不应该返回空值。
    • “引擎根据使用的表达式确定计算列的可空性” - 该引用表示如果列表达式仅由 NOT NULL-able 子表达式组成并且不执行任何可能的操作导致NULL 本身的结果类型为NOT NULL - 到目前为止,一切都很好。但是,据我所知,COUNT(*) never 返回 NULL 并且文档中也没有任何内容涵盖此行为 - 所以除了它是一个 主要未记录的缺点之外还有什么解释/i> 在派生类型分析中?
    • @Dai - COUNT 可以返回NULL
    • @MartinSmith 我问过微软,they're still trying to find out for me
    【解决方案2】:

    为什么 SQL Server 2005 认为 COUNT(...) 可以为空?

    看看下面的例子

    CREATE VIEW Test1 AS
    WITH R216 AS
    (
    SELECT TOP (216) 1 AS X
    FROM master..spt_values
    )
    SELECT COUNT(*) AS X
    FROM R216 a, R216 b, R216 c, R216 d
    

    这与您的示例大致相同。 COUNT 列是从视图中投影出来的

    SELECT COLUMN_NAME, IS_NULLABLE 
    FROM INFORMATION_SCHEMA.COLUMNS 
    WHERE TABLE_NAME = 'Test1'
    

    返回

    +-------------+-------------+
    | COLUMN_NAME | IS_NULLABLE |
    +-------------+-------------+
    | X           | YES         |
    +-------------+-------------+
    

    可以看出这实际上可以返回一个NULL,如下所示。

    SET ANSI_WARNINGS, ARITHABORT OFF;
    
    SELECT * FROM Test1
    

    返回

    +------+
    |  X   |
    +------+
    | NULL |
    +------+
    

    2,176,782,336COUNT 溢出 INT 并且使用上面已弃用的选项 SET 意味着返回 NULL 而不是错误

    ISNULL(,not_null_constant) 包裹意味着该列可以被视为永远不会返回NULL

    上述内容也适用于像 ROW_NUMBER(或几乎任何数学表达式)这样可以返回 NULL 而不会像上面那样溢出的构造。

    通常,即使没有模糊的已弃用 SET 选项,正确确定计算列的可空性也可能很棘手。

    例如,MAX(not_null_column) 在用作矢量聚合时也永远不会返回 NULL(使用 GROUP BY) - 但是它可以在用作标量聚合时返回 NULL一张空桌子。

    在绝大多数情况下,SQL Server 只是假设任何计算表达式都可以为空,并在文档中明确指出这一点,并建议在这种假设可能导致问题的情况下使用 ISNULL

    【讨论】:

    • 但是如果SET ANSI_WARNINGS ON,那么COUNT 不会溢出,只是错误,那么- 不应该返回NULL 那么...?
    • 是的。但是系统表不会为不同的设置选项存储不同的可空性值。无论如何,它们都会返回相同的值。 COUNT 可以在 SELECT 时根据会话选项返回 NULL,因此指示此列不可为空是不正确的
    • 要明确一点,因为大多数情况下,SQL Server 会假设表达式可以为空,除非它们被包裹在 ISNULL 中,而不是任何详尽的逻辑来确定这一点,所以会有很多情况下该列被视为可以为空,并且没有这样的反例是可能的,但对于 COUNT 它有可能产生一个 NULL
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2010-11-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多