我有两张桌子
表1
Column1
_______
1
2
3
4
5
6
表2
Column 1
________
4
NULL //This NULL value added after answering the question, to show the real problem
5
6
7
8
9
这是一个示例案例。我试过的时候,
SELECT column1 FROM Table1 WHERE column1 IN (SELECT column1 FROM Table2)
我得到4,5,6
什么时候
SELECT column1 FROM Table1 WHERE column1 NOT IN (SELECT column1 FROM Table2)
我没有得到1,2,3但是没有。
在实际情况中,table1的column1是nvarchar(max),table2的column1是varchar(50)。但是,我尝试将两者都转换为varchar(50)。
答案 0 :(得分:8)
查看IN
的文档,具体为:
子查询或表达式返回的任何空值,使用IN或NOT IN与 test_expression 进行比较,返回UNKNOWN。将空值与IN或NOT IN一起使用会产生意外结果。
您尚未显示,但我某些您的数据中至少隐藏了一个NULL
值。
您可以排除NULL
(s),然后NOT IN
将按您的预期运作:
SELECT column1 FROM Table1
WHERE column1 NOT IN (SELECT t2.column1 FROM Table2 t2
WHERE t2.column1 IS NOT NULL)
IN
和NOT IN
是对立的,但你必须记住SQL的three-valued logic。想象一下,我们使用表达式形式
IN
a IN (1,2,NULL)
其处理方式与:
相同a = 1 OR a = 2 or a = NULL
对于a = 1的任何行,我们有:
TRUE OR TRUE OR UNKNOWN
是TRUE
。对于a = 3的任何行,比方说,我们有:
FALSE OR FALSE OR UNKNOWN
是UNKNOWN
现在,以同样的方式考虑NOT IN
:
a NOT IN (1,2,NULL)
其处理方式与:
相同a != 1 AND a != 2 AND a != NULL
对于a = 1的任何行,我们有:
FALSE AND TRUE AND UNKNOWN
哪个是FALSE
。对于a = 3,我们有:
TRUE AND TRUE AND UNKNOWN
哪个是UNKNOWN
。 NULL
的存在意味着无法获得此AND
链以产生TRUE
值。
答案 1 :(得分:6)
如果您的Table2中有null
个值,则可能会发生这种情况。请改用此查询:
select *
from Table1 as t1
where not exists (select * from Table2 as t2 where t2.column1 = t1.column1);
<强> sql fiddle demo 强>
测试查询:
-- Table2 doesn't have null values, works good
SELECT column1 FROM Table1 WHERE column1 IN (SELECT column1 FROM Table2);
SELECT column1 FROM Table1 WHERE column1 NOT IN (SELECT column1 FROM Table2);
insert into Table2
select null;
-- nothing returned by query, because of null values in Table2
SELECT column1 FROM Table1 WHERE column1 NOT IN (SELECT column1 FROM Table2);
-- works good
select *
from Table1 as t1
where not exists (select * from Table2 as t2 where t2.column1 = t1.column1);
这是因为three-valued logic的SQL,请参阅Damien_The_Unbeliever nice explanation。您可以使用not null
查询,如下所示:
SELECT column1 FROM Table1 WHERE column1 NOT IN (SELECT column1 FROM Table2 where column1 is not null);
但我更喜欢exists
,因为它会隐式过滤掉null(仅仅因为使用=
)条件。
作为补充,不要在没有别名的问题中使用类似查询的查询(实际上不是别名,而是点符号,如Table.column
或Alias.column
),因为您可以拥有{{3} }。始终对列使用点表示法。所以你的查询应该是这样的:
SELECT t1.column1 FROM Table1 as t1 WHERE t1.column1 NOT IN (SELECT t2.column1 FROM Table2 as t2 where t2.column1 is not null);
答案 2 :(得分:3)
这是他们应该避免NOT IN的主要原因,它基于三向逻辑,YES / NO / UNKNOWN: - )
col IN (1,2,NULL)
is the logically equivalent to
col=1 OR col=2 OR col=NULL
col NOT IN (1,2,NULL)
is the logically equivalent to
col<>1 AND col<>2 AND col<>NULL
现在任何与NULL的比较都计算为UNKNOWN,只有“col IS(NOT)NULL”是正确的。
如果你有ORed条件,UNKNOWN无关紧要,但在ANDed条件下单个UNKNOWN导致最终UNKNOWN。
当您向外部table1添加NULL并从table2中删除NULL时,您会注意到IN / NOT IN答案集中都缺少此行。
最好的解决方法是使用EXISTS / NOT EXISTS,只有YES / NO,因为评估UNKNOWN的条件被忽略了,简单地视为FALSE。