【问题标题】:T-SQL / Unexpected NULL handling when ANSI_NULLS is turned OFFT-SQL / ANSI_NULLS 关闭时的意外 NULL 处理
【发布时间】:2017-07-04 15:20:01
【问题描述】:

我只是在处理 SQL Server 中的 NULL 值(在版本 12.0.5000.0 上测试)。基本上,我的意图是让所有具有列值 的行都为静态值(例如 999)。我不是在寻找替代的 LIKE “使用 ISNULL 函数”。该查询是由第三方引擎生成的,我不打算编写解析器并更改语句。

-- All examples with ANSI_NULLS OFF
SET ANSI_NULLS OFF;
GO

--------------------------------------------------------------------------------------------------------
-- "Virtual" example / working as expected
--------------------------------------------------------------------------------------------------------
    DECLARE 
        @One INT = 1,
        @Null INT = NULL

    SELECT
         IIF(@Null = NULL, 1, 0) '@Null = NULL' -- To test if ANSI_NULL is OFF
        ,IIF(@One <> NULL, 1, 0) '@One <> NULL' -- working with NULL variable
        ,IIF(1 <> NULL, 1, 0) '1 <> NULL'       -- working with NULL value

--------------------------------------------------------------------------------------------------------
-- MSDN Example / NOT working as expected
    -- https://docs.microsoft.com/en-us/sql/t-sql/statements/set-ansi-nulls-transact-sql
--------------------------------------------------------------------------------------------------------

    -- Create table t1 and insert values.  
    CREATE TABLE dbo.t1 (a INT NULL);  
    INSERT INTO dbo.t1 values (NULL),(0),(1);  
    GO  

    -- SET ANSI_NULLS to OFF and test.  
    DECLARE @varname int;  
    SET @varname = 999;

    SELECT a   
    FROM t1   
    WHERE a <> @varname;    -- working with NULL variable

    SELECT a   
    FROM t1   
    WHERE a <> 999;         -- NOT working with NULL value

    -- Drop table t1.  
    DROP TABLE dbo.t1;  

谁能解释为什么“虚拟”示例的工作方式与 MSDN 示例不同?

Virtual example:
+--------------+--------------+-----------+
| @Null = NULL | @One <> NULL | 1 <> NULL |
+--------------+--------------+-----------+
|            1 |            1 |         1 |
+--------------+--------------+-----------+

MSDN example:
-- SELECT 1
+------+
|  a   |
+------+
| NULL |
| 0    |
| 1    |
+------+

-- SELECT 2
+------+
|  a   |
+------+
| 0    |
| 1    |
+------+

【问题讨论】:

    标签: sql sql-server tsql null ansi-nulls


    【解决方案1】:

    看起来查询优化器选择了不同的比较运算符:

    DECLARE @varname int;  
    SET @varname = 999;
    
    SELECT a   
    FROM t1   
    WHERE a <> @varname;
    

    XML 执行计划:

    <Predicate>
        <ScalarOperator ScalarString="[fiddle_84f7799901e54a779e8bff464a2d01f3].[dbo].[t1].[a] &lt;&gt; [@varname]">
            <Compare CompareOp="IS NOT">
                <ScalarOperator>
                    <Identifier>
                        <ColumnReference Database="[fiddle_84f7799901e54a779e8bff464a2d01f3]" Schema="[dbo]" Table="[t1]" Column="a"></ColumnReference>
                    </Identifier>
                </ScalarOperator>
                <ScalarOperator>
                    <Identifier>
                        <ColumnReference Column="@varname"></ColumnReference>
                    </Identifier>
                </ScalarOperator>
            </Compare>
        </ScalarOperator>
    </Predicate> 
    

    比较 CompareOp=“不是”


    使用硬编码值的第二次查询:

    SELECT a   
    FROM t1   
    WHERE a <> 999; 
    
    -- same as
    DECLARE @varname int = 999;
    
    SELECT a   
    FROM t1   
    WHERE a <> (SELECT @varname);
    

    XML 执行计划:

    <Predicate>
        <ScalarOperator ScalarString="[fiddle_ac5121a789da473382366733b51ef441].[dbo].[t1].[a]&lt;&gt;(999)">
            <Compare CompareOp="NE">
                <ScalarOperator>
                    <Identifier>
                        <ColumnReference Database="[fiddle_ac5121a789da473382366733b51ef441]" Schema="[dbo]" Table="[t1]" Column="a"></ColumnReference>
                    </Identifier>
                </ScalarOperator>
                <ScalarOperator>
                    <Const ConstValue="(999)"></Const>
                </ScalarOperator>
            </Compare>
        </ScalarOperator>
    </Predicate>
    

    比较 CompareOp="NE"

    DBFiddle

    编辑:

    SET ANSI_NULLS

    仅当比较的操作数之一是 NULL 变量或文字 NULL 时,SET ANSI_NULLS ON 才会影响比较。 如果比较的两边都是列或复合表达式,则设置不影响比较。

    【讨论】:

    • 嘿小伙子,谢谢你的回答。不是我期望/希望阅读的,但听起来我必须找到另一个解决方案;-)
    猜你喜欢
    • 1970-01-01
    • 2012-09-09
    • 1970-01-01
    • 2015-12-08
    • 2021-05-03
    • 2020-07-23
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多