sql not in 发生歧义的问题

1.SELECT COUNT(*) FROM usergrade ug WHERE ug.username NOT IN (SELECT ut.USERNAME FROM usertable ut)
SELECT * FROM usergrade ug WHERE ug.username NOT IN ('user1','user3','user5','user6','NULL','NULL')




为啥上面两个的结果不一样呢?


SELECT * FROM usergrade ug WHERE ug.username NOT IN ('user1','user3','user5','user6',NULL,NULL)
如果改成这个得到的结果就是零,为啥?


这个语句可以,为啥后面的两个语句不对呢


SELECT COUNT(*) FROM usergrade ug WHERE ug.username NOT EXISTS (SELECT * FROM usertable ut)



This issue came up when I got different records counts for what I thought were identical queries one using a not in where constraint and the other a left join. The table in the not in constraint had one null value (bad data) which caused that query to return a count of 0 records. I sort of understand why but I could use some help fully grasping the concept.

To state it simply, why does query A return a result but B doesn't?

A: select 'true' where 3 in (1, 2, 3, null)
B: select 'true' where 3 not in (1, 2, null)

This was on SQL Server 2005. I also found that calling set ansi_nulls off causes B to return a result.

share | improve this question
 
 

11 Answers

up vote 75 down vote accepted

Query A is the same as:

select 'true' where 3 = 1 or 3 = 2 or 3 = 3 or 3 = null

Since 3 = 3 is true, you get a result.

Query B is the same as:

select 'true' where 3 <> 1 and 3 <> 2 and 3 <> null

When ansi_nulls is on, 3 <> null is UNKNOWN, so the predicate evaluates to UNKNOWN, and you don't get any rows.

When ansi_nulls is off, 3 <> null is true, so the predicate evaluates to true, and you get a row.

share | improve this answer
 
8 
one correction: it is actually 3 value logic, so 3 <> NULL is not FALSE but UNKNOWN if it was false the query NOT (3 <> null) would evaluate to True but it is not - it is still UNKNOWN. You can test it by calling select 'true' where 3 in (null) select 'true' where 3 not in(null) -both give no result –  kristof Sep 25 '08 at 9:25
 
@kristof: Yes, you're right. I will correct my answer. –  Brannon Sep 25 '08 at 17:05
1 
Has anybody ever pointed out that converting NOT IN to a series of <> and changes the semantic behavior of not in this set to something else? –  Ian Boyd Oct 13 '10 at 14:47
2 
@Ian - It looks like "A NOT IN ( 'X', 'Y' )" actually is an alias for A <> 'X' AND A <> 'Y' in SQL. (I see that you discovered this yourself in stackoverflow.com/questions/3924694/…, but wanted to make sure your objection was addressed in this question.) –  Ryan Olson Dec 27 '10 at 19:21
No problem. We won't show you that ad again. Why didn't you like it?
Oops! I didn't mean to do this.

Whenever you use NULL you are really dealing with a Three-Valued logic.

Your first query returns results as the WHERE clause evaluates to:

    3 = 1 or 3 = 2 or 3 = 3 or 3 = null
which is:
    FALSE or FALSE or TRUE or UNKNOWN
which evaluates to 
    TRUE

The second one:

    3 <> 1 and 3 <> 2 and 3 <> null
which evaluates to:
    TRUE and TRUE and UNKNOWN
which evaluates to:
    UNKNOWN

The UNKNOWN is not the same as FALSE you can easily test it by calling:

select 'true' where 3 <> null
select 'true' where not (3 <> null)

Both queries will give you no results

If the UNKNOWN was the same as FALSE then assuming that the first query would give you FALSE the second would have to evaluate to TRUE as it would have been the same as NOT(FALSE).
That is not the case.

There is a very good article on this subject on SqlServerCentral (website requires regisration)

The whole issue of NULLs and Three-Valued Logic can be a bit confusing at first but it is essential to understand in order to write correct queries in TSQL

Some other read I would recommend is SQL Aggregate Functions and NULL (website requires regisration)

Hope that helps, 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值