NOT
is always a negation. The reason for this behaviour of T-SQL lies in the fact that null
values are treated in a special way depending on a database configuration setting (known as ansi_nulls
). Depending on this setting, null
is either treated in the same way as any other value or it is treated as "value not set". In this case, all expressions containing null values are regarded as invalid.
Furthermore, the expression
(@a IS NULL AND @b IS NULL)
OR
@a = @b
covers only the case when both variables are NULL
, it does not deal with cases when either @a
or @b
is NULL
. If that happens, the result depends on the setting of ansi_nulls
: if it is on
, then the result of @a = @b
is always false
if one of the variables is NULL
.
If ansi_nulls
is off
, then NULL
is treated as a value and behaves as you expect.
To avoid such unexpected behaviour, you should cover all cases as follows:
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
Note that in this example all null cases are dealt with before the @a=@b
case is checked (in a CASE
statement, the WHEN
's are processed in the order as they appear, and if a condition matches, processing is finished and the specified value is returned).
To test all possible (relevant) combinations, you can use this script:
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
It returns:
In other words, in this script null
is treated as a value, hence a='a'
and b=null
returns 0
, which is what you've expected. Only if both variables are equal (or both null
), it returns 1
.
set ansi_nulls off;
in front of your query and you'll see the difference. Then you don't get aNULL
from comparisons where at least one operarand isNULL
but afalse
. – FinalismIS DISTICT FROM
operator (<=>
in MySQL). – Theomorphic