代码之家  ›  专栏  ›  技术社区  ›  Matthew Vines

奇怪的SQL行为,我想知道为什么它是这样工作的

  •  2
  • Matthew Vines  · 技术社区  · 16 年前

    考虑下面的Transact-SQL。

    DECLARE @table TABLE(val VARCHAR(255) NULL)
    
    INSERT INTO @table (val) VALUES('a')
    INSERT INTO @table (val) VALUES('b')
    INSERT INTO @table (val) VALUES('c')
    INSERT INTO @table (val) VALUES('d')
    INSERT INTO @table (val) VALUES(NULL)
    
    select val 
    from @table
    where val not in ('a') 
    

    我希望这个能回来

    b, c, d, NULL
    

    但是它却回来了

    b, c, d
    

    为什么会这样?是否未计算空值?在集合“a”中是否为空?

    5 回复  |  直到 16 年前
        1
  •  3
  •   Marcus Adams    16 年前

    答案

    默认情况下,对于SQL,空表示“未知”。所以,任何与“未知”的比较都是“未知”。

    例如,如果一个陌生人站在鲍勃旁边,你想问一个问题,“陌生人的名字和鲍勃的名字一样吗?”。答案未知。

    既然你在问,“返回任何值不是‘A’的记录”。当它到达这个空列时,SQL仍然说,“我不知道”。因为表达式的计算结果不是真的,所以不会返回该记录。

    解决方案

    将空值与常量进行比较的任何表达式都将始终为空,因此请使用 IS NULL IS NOT NULL 测试空值。

    这会让你 b , c ,请 d NULL :

    SELECT val 
    FROM @table
    WHERE val NOT IN ('a') OR val IS NULL
    

    解决方法

    可以更改空值的默认行为:

    SET ANSI_NULLS OFF
    
        2
  •  3
  •   KM.    16 年前

    要获取空行,请尝试:

    select val 
    from @table
    where val not in ('a') OR val IS NULL
    

    试试这些:

    select 1 where null in (null)
    select 1 where null in (1)
    select 1 where 1 in (null)
    

    全部返回零行

    空=空始终为假 空=anythng始终为假 ,当测试空行时,where子句在(“a”)中为空,因此始终为假。

        3
  •  2
  •   HLGEM    16 年前

    不能直接将空值与任何值进行比较。

    尝试

    select val  
    from @table 
    where coalesce(val, '') not in ('a')  
    
        4
  •  2
  •   CResults    16 年前

    用这种方法不能对空进行相等。

    考虑这个

    select case when 'a' = NULL then 1 else 0 end
    select case when 'a' <> NULL then 1 else 0 end
    

    上面你会得到

    result
    ------
      0
      0
    

    对于您的查询,请尝试

     where isnull(val,'') not in ('a') 
    
        5
  •  2
  •   Quesi    16 年前

    试试这个,你会得到一个不同的答案:

    set ansi_nulls off;
    DECLARE @table TABLE(val VARCHAR(255) NULL)
    
    INSERT INTO @table (val) VALUES('a')
    INSERT INTO @table (val) VALUES('b')
    INSERT INTO @table (val) VALUES('c')
    INSERT INTO @table (val) VALUES('d')
    INSERT INTO @table (val) VALUES(NULL)
    
    select val 
    from @table
    where val not in ('a')
    

    您已经打开了ansi_nulls,因此它会相应地处理nulls。