2017-07-04 47 views
3

我只是在SQL Server中處理NULL值(在版本12.0.5000.0上測試過)。基本上,我的意圖是獲得列值爲一個靜態值(例如999)的所有行。我不是在尋找替代LIKE「使用ISNULL函數」。查詢由第三方引擎生成,我不打算編寫解析器並更改語句。當ANSI_NULLS被關閉時,T-SQL /意外的NULL處理

-- 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 | 
+------+ 

回答

2

貌似查詢優化器選擇不同的比較操作:

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

SET ANSI_NULLS ON僅影響,如果比較的其中一個操作數可以是一個變量,它是NULL或文字NULL的比較。 如果比較的兩邊都是列或複合表達式,則該設置不會影響比較。

+1

嘿,小夥子,謝謝你的回答。不是我期望/希望閱讀但聽起來像我必須找到另一個解決方案;-) – MBauer