Using SQL Server 2000, in Query Analyzer both of these statements
properly return "This is NOT null" for columns that are null. The first
uses 'simple CASE' and the second uses 'searched CASE'. POLICY_ID is a
char column.
SELECT policy_id, CASE policy_id WHEN NULL THEN 'This is NULL' ELSE
'This is NOT null' END
FROM SUBM
WHERE policy_id is null
SELECT policy_id, CASE WHEN policy_id IS NULL THEN 'This is NULL' else
'This is NOT null' END
FROM SUBM
WHERE policy_id is null
However, in CAST SQL-Builder which I use for writing stored procedures,
the simple CASE function returns 'This is NOT null' for all rows, even
those where policy_id IS NULL. Somehow it's not properly reading the
NULL values as genuine NULLs and returning false on the "CASE policy_id
WHEN NULL". Any thoughts on this? Is the simple CASE sometimes
problematic when testing against NULLs? Thanks.
Plamen Ratchev - 29 Jul 2008 22:59 GMT
The correct way to compare to NULL is always to use IS NULL as in the
searched CASE you have. The behavior you experience is due to setting
ANSI_NULLS to OFF, which forces SQL Server to differ from the SQL standard
and evaluate NULL = NULL.
If you explicitly use SET ANSI_NULLS ON you will see the standard behavior.
This is not a problem with simple CASE, just the way NULLs are compared.
You can do something like this (assuming -1 is invalid policy number):
CASE COALESCE(policy_id, -1)
WHEN -1 THEN 'This is NULL'
ELSE 'This is NOT null'
END
Plamen Ratchev
http://www.SQLStudio.com
Roy Harvey (SQL Server MVP) - 29 Jul 2008 23:04 GMT
>Using SQL Server 2000, in Query Analyzer both of these statements
>properly return "This is NOT null" for columns that are null. The first
[quoted text clipped - 17 lines]
>WHEN NULL". Any thoughts on this? Is the simple CASE sometimes
>problematic when testing against NULLs? Thanks.
Sounds like a good reason to write stored procedures in Query
Analyzer.
If this tool is helping you write stored procedures I assume the
procedures end up as Transact-SQL stored procedures. It sounds like
something is wrong with the T-SQL. You need to inspect that code, or
post it here for more widespread inspection.
Just as an aside, I almost always use the form CASE WHEN <comparison>,
and would not use anything else when a test for NULL was required.
Roy Harvey
Beacon Falls, CT
David Portas - 29 Jul 2008 23:15 GMT
> Using SQL Server 2000, in Query Analyzer both of these statements
> properly return "This is NOT null" for columns that are null. The first
[quoted text clipped - 17 lines]
> WHEN NULL". Any thoughts on this? Is the simple CASE sometimes
> problematic when testing against NULLs? Thanks.
CASE policy_id WHEN NULL
is shorthand for
CASE WHEN policy_id = NULL
which always evaluates as "UNKNOWN" therefore the ELSE clause is always
returned as a result.
Instead you'll have to use searched CASE or use only non-null expressions in
the simple CASE.

Signature
David Portas
Alex Kuznetsov - 29 Jul 2008 23:29 GMT
> Using SQL Server 2000, in Query Analyzer both of these statements
> properly return "This is NOT null" for columns that are null. The first
[quoted text clipped - 17 lines]
> WHEN NULL". Any thoughts on this? Is the simple CASE sometimes
> problematic when testing against NULLs? Thanks.
also read about SET ANSI_NULLS ON setting
--CELKO-- - 30 Jul 2008 13:21 GMT
The CASE expression is an *expression* and not a control statement;
that is, it returns a value of one data type. SQL-92 stole the idea
and the syntax from the ADA programming language. Here is the BNF for
a <case specification>:
<case specification> ::= <simple case> | <searched case>
<simple case> ::=
CASE <case operand>
<simple when clause>...
[<else clause>]
END
<searched case> ::=
CASE
<searched when clause>...
[<else clause>]
END
<simple when clause> ::= WHEN <when operand> THEN <result>
<searched when clause> ::= WHEN <search condition> THEN <result>
<else clause> ::= ELSE <result>
<case operand> ::= <value expression>
<when operand> ::= <value expression>
<result> ::= <result expression> | NULL
<result expression> ::= <value expression>
The searched CASE expression is probably the most used version of the
expression. The WHEN ... THEN ... clauses are executed in left to
right order. The first WHEN clause that tests TRUE returns the value
given in its THEN clause. And, yes, you can nest CASE expressions
inside each other. If no explicit ELSE clause is given for the CASE
expression, then the database will insert a default ELSE NULL clause.
If you want to return a NULL in a THEN clause, then you must use a
CAST (NULL AS <data type>) expression. I recommend always giving the
ELSE clause, so that you can change it later when you find something
explicit to return.
The <simple case expression> is defined as a searched CASE expression
in which all the WHEN clauses are made into equality comparisons
against the <case operand>. For example
CASE iso_sex_code
WHEN 0 THEN 'Unknown'
WHEN 1 THEN 'Male'
WHEN 2 THEN 'Female'
WHEN 9 THEN 'N/A'
ELSE NULL END
could also be written as:
CASE
WHEN iso_sex_code = 0 THEN 'Unknown'
WHEN iso_sex_code = 1 THEN 'Male'
WHEN iso_sex_code = 2 THEN 'Female'
WHEN iso_sex_code = 9 THEN 'N/A'
ELSE NULL END
There is a gimmick in this definition, however. The expression
CASE foo
WHEN 1 THEN 'bar'
WHEN NULL THEN 'no bar'
END
becomes
CASE WHEN foo = 1 THEN 'bar'
WHEN foo = NULL THEN 'no_bar' -- error!
ELSE NULL END
The second WHEN clause is always UNKNOWN.
The SQL-92 Standard defines other functions in terms of the CASE
expression, which makes the language a bit more compact and easier to
implement. For example, the COALESCE () function can be defined for
one or two expressions by
1) COALESCE (<value exp #1>) is equivalent to (<value exp #1>)
2) COALESCE (<value exp #1>, <value exp #2>) is equivalent to
CASE WHEN <value exp #1> IS NOT NULL
THEN <value exp #1>
ELSE <value exp #2> END
then we can recursively define it for (n) expressions, where (n >= 3),
in the list by
COALESCE (<value exp #1>, <value exp #2>, . . ., n), as equivalent to:
CASE WHEN <value exp #1> IS NOT NULL
THEN <value exp #1>
ELSE COALESCE (<value exp #2>, . . ., n)
END
Likewise, NULLIF (<value exp #1>, <value exp #2>) is equivalent to:
CASE WHEN <value exp #1> = <value exp #2>
THEN NULL
ELSE <value exp #1> END
It is important to be sure that you have a THEN or ELSE clause with a
data type that the compiler can find to determine the highest data
type for the expression.
A trick in the WHERE clause is use it for a complex predicate with
material implications.
WHERE CASE
WHEN <search condition #1>
THEN 1
WHEN <search condition #2>
THEN 1
...
ELSE 0 END = 1
Gert-Jan Strik posted some examples of how ISNULL() and COALESCE() on
2004 Aug 19
CREATE TABLE #t(a CHAR(1));
INSERT INTO #t VALUES (NULL);
SELECT ISNULL(a,'abc') FROM #t;
SELECT COALESCE(a, 'abc') FROM #t;
DROP TABLE #t;
He always use COALESCE, with the exception of the following type of
situation, because of its performance consequences:
SELECT ...,
ISNULL((SELECT COUNT(*) -- or other aggregate
FROM B
WHERE B.key = A.key), 0)
FROM A;
Likewise, Alejandro Mesa cam up with this example:
SELECT 13 / COALESCE(CAST(NULL AS INTEGER), 2.00); -- promote to
highest type (decimal)
SELECT 13 / ISNULL(CAST(NULL AS INTEGER), 2.00); -- promote to first
type (integer)
Gert-Jan Strik - 30 Jul 2008 20:52 GMT
> Gert-Jan Strik posted some examples of how ISNULL() and COALESCE() on
> 2004 Aug 19
[quoted text clipped - 13 lines]
> WHERE B.key = A.key), 0)
> FROM A;
Joe, for your information: my archive shows that I got both pieces of
information from a thread on 27 January 2002 (the 2 final posts):
http://groups.google.com/group/microsoft.public.sqlserver.programming/browse_thr
ead/thread/a7e0e03075659310/76480935c311b702

Signature
Gert-Jan
SQL Server MVP