4

我有两张桌子

表格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 而是 NULL

在实际情况下,table1 的 column1 是 nvarchar(max),table2 的 column1 是 varchar(50)。但是,我尝试将两者都转换为 varchar(50)。

4

3 回答 3

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 的三值逻辑。想象一下,我们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意味着永远无法让这个ANDs 链产生一个TRUE值。

于 2013-09-18T06:25:20.377 回答
6

如果您null的 Table2 中有值,则可能会发生这种情况。请改用此查询:

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

这是因为SQL 的三值逻辑,请参阅 Damien_The_Unbeliever很好的解释。您可以使用not null查询,如下所示:

SELECT column1 FROM Table1 WHERE column1 NOT IN (SELECT column1 FROM Table2 where column1 is not null);

但我exists更喜欢,因为它隐式过滤掉 null (只是因为使用=)条件。

另外,不要在没有别名的问题中使用类似查询(实际上不是别名,而是点表示法,例如Table.columnor Alias.column),因为您可能会得到不正确的结果。始终为您的列使用点符号。所以你的查询应该是这样的:

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);
于 2013-09-18T06:26:46.770 回答
3

这是您应该避免 NOT IN 的主要原因,它基于三路逻辑,是/否/未知 :-)

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。

当您将 NULL 添加到外部 table1 并从 table2 中删除 NULL 时,您会注意到在两个 IN/NOT IN 答案集中都缺少该行。

最好的解决方法是使用 EXISTS/NOT EXISTS,只有 YES/NO,因为评估为 UNKNOWN 的条件有点被忽略并简单地视为 FALSE。

于 2013-09-18T06:44:28.280 回答