Warning: file_get_contents(/data/phpspider/zhask/data//catemap/7/sql-server/27.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Sql server 什么时候是;不是";不是否定吗?_Sql Server_Tsql_Null_Expression_Evaluation - Fatal编程技术网

Sql server 什么时候是;不是";不是否定吗?

Sql server 什么时候是;不是";不是否定吗?,sql-server,tsql,null,expression,evaluation,Sql Server,Tsql,Null,Expression,Evaluation,为什么下面两个都返回零?第二个肯定是第一个的否定吗?我正在使用SQLServer2008 DECLARE @a VARCHAR(10) = NULL , @b VARCHAR(10) = 'a' SELECT CASE WHEN ( ( @a IS NULL AND @b IS NULL ) OR @a = @b

为什么下面两个都返回零?第二个肯定是第一个的否定吗?我正在使用SQLServer2008

DECLARE 
    @a VARCHAR(10) = NULL ,
    @b VARCHAR(10) = 'a'

SELECT  
    CASE WHEN ( ( @a IS NULL
                      AND @b IS NULL
                    )
                    OR @a = @b
                  ) THEN 1
         ELSE 0
    END , -- Returns 0
    CASE WHEN NOT ( ( @a IS NULL
                      AND @b IS NULL
                    )
                    OR @a = @b
                  ) THEN 1
         ELSE 0
    END -- Also returns 0

这是一种否定。但是,您需要了解ANSI NULL-NULL的否定也是NULL。NULL是一个虚假的真值

因此,如果您的任何参数为null,则
@a=@b
的结果将为null(falsy),对该参数的否定也将为null(falsy)

要想按您想要的方式使用否定,您需要去掉NULL。但是,简单地反转比较结果可能更容易:

case when (...) then 1 else 0 end,
case when (...) then 0 else 1 end
它将始终为您提供
1,0
0,1

编辑:

正如jpmc26所指出的,对NULL的行为进行一点扩展可能会很有用,这样您就不会认为一个
NULL
将使一切
NULL
。有些运算符在其一个参数为null时并不总是返回
null
——最明显的例子当然是
为null

在更广泛的示例中,T-SQL中的逻辑运算符使用Kleene代数(或类似的东西),它定义了
表达式的真值,如下所示:

  | T | U | F
T | T | T | T
U | T | U | U
F | T | U | F
与其他运算符类似)

因此,您可以看到,如果至少有一个参数为true,那么结果也将为true,即使另一个参数为未知(“null”)。这也意味着
not(T或U)
会给你一个虚假的真值,而
not(F或U)
也会给你一个虚假的真值,尽管
F或U
是虚假的,因为
F或U
U
也是虚假的


这对于解释当两个参数都为null时表达式为何按预期方式工作很重要,
@a为null,@b为null
计算结果为true,
true或unknown
计算结果为
true

这是@a=@b的问题如果这两个值中的任何一个都为null,那么它就是问题

如果您尝试下面的代码将给出正确的结果

DECLARE 
    @a VARCHAR(10) = NULL ,
    @b VARCHAR(10) = 'a'

SELECT  
    CASE WHEN ( ( @a IS NULL
                      AND @b IS NULL
                    )
                    OR @a = @b
                  ) THEN 1
         ELSE 0
    END , -- returns 0
    CASE WHEN NOT ( ( @a IS NULL
                      AND @b IS NULL
                    )
                    OR ISNULL(@a,-1) = ISNULL(@b,-1)
                  ) THEN 1
         ELSE 0
    END -- also returns 0

您遇到的这种“奇怪”行为是由
NULL
值引起的

NOT(返回NULL的事物)
的否定不是
TRUE
,它仍然是
NULL

例如


这将使优化器将
NULL
视为正常值,并返回
TRUE\FALSE
。你应该注意,这是不推荐的,你应该避免

NOT
总是一个否定词。T-SQL的这种行为的原因在于,
null
值根据数据库配置设置(称为
ansi_nulls
)以特殊方式处理。根据此设置,
null
或以与任何其他值相同的方式处理,或被视为“未设置值”。在这种情况下,所有包含空值的表达式都被视为无效

此外,表达式

(@a IS NULL AND @b IS NULL)
OR 
@a = @b
仅涵盖两个变量均为
NULL
时的情况,不处理
@a
@b
NULL
时的情况。如果发生这种情况,结果取决于
ansi_nulls
的设置:如果
上,那么
@a=@b
的结果总是
false
,如果其中一个变量是
NULL

如果
ansi_nulls
off
,则
NULL
将被视为一个值,其行为与您期望的一样

为避免此类意外行为,您应涵盖以下所有情况:

DECLARE 
    @a VARCHAR(10) = 'a',
    @b VARCHAR(10) = null

SELECT  
    CASE 
        WHEN (@a IS NOT null AND @b IS null) THEN 0
        WHEN (@a IS null AND @b IS NOT null) THEN 0
        WHEN (@a IS null AND @b IS null) THEN 1
        WHEN (@a=@b) THEN 1
    ELSE 0
    END 
注意在本例中,在检查
@a=@b
案例之前,将处理所有空案例(在
案例
语句中,按照出现的顺序处理
,如果条件匹配,则处理完成并返回指定值)


要测试所有可能的(相关)组合,可以使用以下脚本:

DECLARE @combinations TABLE (
    a VARCHAR(10),b VARCHAR(10)
    )

INSERT INTO @combinations
    SELECT 'a', null 
    UNION SELECT null, 'b'
    UNION SELECT 'a', 'b'
    UNION SELECT null, null
    UNION SELECT 'a', 'a'

SELECT a, b,
    CASE 
        WHEN (a IS NOT null AND b IS null) THEN 0
        WHEN (a IS null AND b IS NOT null) THEN 0
        WHEN (a IS null AND b IS null) THEN 1
        WHEN (a=b) THEN 1
    ELSE 0
    END as result
from @combinations
order by result 
它返回:


换句话说,在这个脚本中,
null
被视为一个值,因此
a='a'
b=null
返回
0
,这是您所期望的。仅当两个变量相等时(或同时
null
),它返回
1

设置为空在您的查询前面,您将看到差异。然后,在至少有一个运算符且为
NULL
的比较中,不会得到
NULL
,但@Luaan的答案是100%正确的。但是,您可能正在查找
运算符(
在MySQL中)之间的差异。显然,2008年以后的SQL Server版本将不允许您设置ansi NULL。也就是说,如果您重新构建存储过程,这些版本将强制它们具有“正确”的行为,如果您有依赖于错误行为的遗留代码,那么您就有麻烦了。你可能有很多重写工作要做。下面是一篇关于那些邪恶的ansi空值的好博文:“虚假真值”是什么意思?@nosaid编译器它意味着一个行为类似虚假的真值。@Mickey如果事情是这样的,ansi空值是非常有用的。这只是意味着您需要了解NULL是如何工作的——NULL是未知的,而不是零
0+NULL
没有意义,让它引起错误比假定的解决方法更糟糕。主要的问题是,如果您接受主语言的所有假设,并假设它们在SQL(以及SQL的所有变体)中的工作方式相同。例如,T-SQL根本没有布尔类型——您不能声明truthy变量。这会引起很多混乱,尤其是当人们认为
是一个布尔值时。@jpmc26哦,我明白你现在指的是什么了。我并没有说所有操作符都传播
null
s(至少可以说,这会使
为null
非常不可能),但是
DECLARE 
    @a VARCHAR(10) = 'a',
    @b VARCHAR(10) = null

SELECT  
    CASE 
        WHEN (@a IS NOT null AND @b IS null) THEN 0
        WHEN (@a IS null AND @b IS NOT null) THEN 0
        WHEN (@a IS null AND @b IS null) THEN 1
        WHEN (@a=@b) THEN 1
    ELSE 0
    END 
DECLARE @combinations TABLE (
    a VARCHAR(10),b VARCHAR(10)
    )

INSERT INTO @combinations
    SELECT 'a', null 
    UNION SELECT null, 'b'
    UNION SELECT 'a', 'b'
    UNION SELECT null, null
    UNION SELECT 'a', 'a'

SELECT a, b,
    CASE 
        WHEN (a IS NOT null AND b IS null) THEN 0
        WHEN (a IS null AND b IS NOT null) THEN 0
        WHEN (a IS null AND b IS null) THEN 1
        WHEN (a=b) THEN 1
    ELSE 0
    END as result
from @combinations
order by result