SQL NOT IN不工作

时间:2011-03-08 11:17:55

标签: sql sql-server

我有两个数据库,一个包含清单,另一个包含主数据库记录的子集。

以下SQL语句无效:

SELECT  stock.IdStock
        ,stock.Descr       
FROM    [Inventory].[dbo].[Stock] stock
WHERE   stock.IdStock NOT IN
        (SELECT foreignStockId FROM
         [Subset].[dbo].[Products])

不是不起作用。删除NOT会得到正确的结果,即两个数据库中的产品。但是,使用NOT IN并不会返回任何结果。

我做错了什么,有什么想法?

4 个答案:

答案 0 :(得分:153)

SELECT foreignStockId
FROM   [Subset].[dbo].[Products]  

可能会返回NULL

如果NOT IN值列表中存在任何NULLNOT IN查询将不会返回任何行。您可以使用IS NOT NULL明确排除它们,如下所示。

SELECT stock.IdStock,
       stock.Descr
FROM   [Inventory].[dbo].[Stock] stock
WHERE  stock.IdStock NOT IN (SELECT foreignStockId
                             FROM   [Subset].[dbo].[Products]
                             WHERE  foreignStockId IS NOT NULL) 

或者使用NOT EXISTS重写。

SELECT stock.idstock,
       stock.descr
FROM   [Inventory].[dbo].[Stock] stock
WHERE  NOT EXISTS (SELECT *
                   FROM   [Subset].[dbo].[Products] p
                   WHERE  p.foreignstockid = stock.idstock) 

除了拥有您想要的语义之外,NOT EXISTS的执行计划通常更简单as looked at here

行为差异的原因是SQL中使用的three valued logic。谓词可以评估为TrueFalseUnknown

WHERE子句必须评估为True才能返回行,但NOT IN出现NULL时无法执行此操作,如下所述。< / p>

'A' NOT IN ('X','Y',NULL)相当于'A' <> 'X' AND 'A' <> 'Y' AND 'A' <> NULL)

  • 'A'&lt;&gt; 'X'= True
  • 'A'&lt;&gt; 'Y'= True
  • 'A'&lt;&gt; NULL = Unknown

True AND True AND Unknown根据truth tables for three valued logic评估为Unknown

以下链接对各种选项的表现进行了一些额外的讨论。

答案 1 :(得分:2)

如果 NOT IN 不起作用,您可以尝试 LEFT JOIN 。然后使用连接表中的一个值 NULL WHERE 进行过滤。但是,加入的值不包含任何 NULL 值。

答案 2 :(得分:0)

您还可以使用Case子句来解决此类问题

SELECT  stock.IdStock
        ,stock.Descr        
FROM    [Inventory].[dbo].[Stock] stock
WHERE   (Case when stock.IdStock IN
        (SELECT foreignStockId FROM
        [Subset].[dbo].[Products]) then 1 else 0 end) = 0 

此语法适用于SQL Server,Oracle和postgres

答案 3 :(得分:0)

加上我的2美分:

即使在损坏的数据库中切换到not existsleft join-,我也看到SQL Server返回错误的结果。在所涉及的表上运行DBCC CHECKTABLE,还要查看NOT IN查询执行计划并重建所涉及的索引,这将有所帮助。