如何在SQL Server中正确比较两个可以为空的BIT值?

时间:2017-02-01 17:07:01

标签: sql-server

SQL Server中可以为空的BIT值有3个可能的值:null,0和1.我有两列都是可以为空的BIT,我想知道它们在“NULL”的意义上何时“相等”等于“a NULL和1等于1,0不等于”NULL。但是,我所有的CASE陈述都未能给出我想要的答案。准确地进行这种比较的最佳方法是什么?

DECLARE @BitComparison TABLE
(
  OldValue BIT, 
  NewValue BIT,
  ActuallyEqual VARCHAR(10)
)

INSERT INTO @BitComparison (OldValue, NewValue, ActuallyEqual)
VALUES 
    (null,null,'equal'),
    (null,0,'not equal'),
    (null,1,'not equal'),
    (0,null,'not equal'),
    (0,0,'equal'),
    (0,1,'not equal'),
    (1,null,'not equal'),
    (1,0,'not equal'),
    (1,1,'equal')

SELECT *
, CASE WHEN OldValue <> NewValue then 'not equal' else 'equal' end as 'ComparisonTestA'
, CASE WHEN ISNULL(OldValue, 0) <> ISNULL(NewValue, 0) then 'not equal' else 'equal' end as 'ComparisonTestB'
, CASE WHEN ISNULL(OldValue, -1) <> ISNULL(NewValue, -1) then 'not equal' else 'equal' end as 'ComparisonTestC'
FROM @BitComparison

根据上面的脚本,硬编码的ActuallyEqual列中的值都不匹配ComparisonTest列中的值。我可以将哪些内容添加到SELECT中以动态匹配ActuallyEqual列?

3 个答案:

答案 0 :(得分:3)

使用IS NULL进行NULL检查

CASE
    WHEN OldValue = NewValue
        OR ( OldValue IS NULL AND NewValue IS NULL ) THEN 'equal'
    ELSE 'not equal'
END AS 'ComparisonTestA'

答案 1 :(得分:2)

已发布的解决方案是我能想到的最简单的解决方案。这是一个小小的变化:

CASE WHEN OldValue = NewValue 
        OR ISNULL(NewValue, OldValue) IS NULL THEN 'Equal' ELSE 'Not Equal' END

但我想补充说明为什么你的每个表达都不起作用

CASE WHEN OldValue <> NewValue THEN 'not equal' ELSE 'equal' END

NULL <> Anything而失败,因为NULL因此当任一值为NULL时,它将落入ELSE语句并返回equal

CASE WHEN ISNULL(OldValue, 0) <> ISNULL(NewValue, 0) THEN 'not equal' ELSE 'equal' END

当其中任何一个值为NULL时,它会被替换为0,因此当一个值为NULL而另一个为0时,这两个值将被识别为匹配

CASE WHEN ISNULL(OldValue, -1) <> ISNULL(NewValue, -1) THEN 'not equal' ELSE 'equal' END

这看起来应该有效,但由于ISNULL将返回第一个参数的数据类型,-1将转换为1(可以看到SELECT CONVERT(BIT, -1) 1}}),因此当一个值为1而另一个为null时,这将错误地识别匹配。

考虑到这一点,您还可以将ISNULL换成COALESCE

CASE WHEN COALESCE(OldValue, -1) = COALESCE(NewValue, -1) THEN 'equal' ELSE ' not equal' END

由于COALESCE将返回具有最高优先级(INT > BIT)的数据类型,而不是第一个参数的数据类型。

答案 2 :(得分:2)

使用 CONCAT(),这是一个有趣的选择。

SELECT OldValue,NewValue,ActuallyEqual
     , Test = IIF(concat(OldValue,'-',NewValue) = concat(NewValue,'-',OldValue),'equal','not equal')
FROM @BitComparison

返回

OldValue    NewValue    ActuallyEqual   Test
NULL        NULL        equal           equal
NULL        0           not equal       not equal
NULL        1           not equal       not equal
0           NULL        not equal       not equal
0           0           equal           equal
0           1           not equal       not equal
1           NULL        not equal       not equal
1           0           not equal       not equal
1           1           equal           equal