开发者

Odd SQL behavior, I'm wondering why this works the way it does

开发者 https://www.devze.com 2022-12-24 00:05 出处:网络
Consider the following Transact sql. DECLARE @table TABLE(val VARCHAR(25开发者_C百科5) NULL) INSERT INTO @table (val) VALUES(\'a\')

Consider the following Transact sql.

DECLARE @table TABLE(val VARCHAR(25开发者_C百科5) 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') 

I would expect this to return

b, c, d, NULL

but instead it returns

b, c, d

Why is this the case? Is NULL not evaluated? Is NULL somehow in the set 'a'?


The Answer

By default, NULL, to SQL, means "unknown". So, any comparison to "unknown" is "unknown".

For example, if a stranger is standing next to Bob, and you want to ask the question, "Is the stranger's name the same as Bob's?". The answer is unknown.

Since you're asking, "Return any records where the value is not 'A'". When it gets to that NULL column, SQL still says, "I don't know". Since the expression doesn't evaluate to true, that record isn't returned.

The Solution

Any expression that compares NULL to a constant will always be NULL, so use the special IS NULL and IS NOT NULL to test for NULL values.

This will get you b, c, d, and NULL:

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

The Workaround

You can change the default behavior for NULLs:

SET ANSI_NULLS OFF


to get the null row try:

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

try these:

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

all return zero rows

null=null is always false and null=anythng is always false, when testing the NULL row the WHERE clause is WHERE NULL in ('a'), so it is always false.


Null can't be directly compared to anything.

try

select val  
from @table 
where coalesce(val, '') not in ('a')  


You can't do equality with NULL in this way.

Consider this

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

For above you'll get

result
------
  0
  0

For your query try

 where isnull(val,'') not in ('a') 


Try this and you will get a different answer:

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')

You have ansi_nulls on and so it treats nulls accordingly.

0

精彩评论

暂无评论...
验证码 换一张
取 消