SQL NOT IN 不工作

Posted

技术标签:

【中文标题】SQL NOT IN 不工作【英文标题】:SQL NOT IN not working 【发布时间】:2011-03-08 11:17:55 【问题描述】:

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

以下 SQL 语句不起作用:

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

not in 不起作用。删除 NOT 会给出正确的结果,即两个数据库中的产品。但是,使用 NOT IN 根本不会返回任何结果。

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

【问题讨论】:

你确定你有 stock.IdStock 根本不在 foreignStockId 中吗? 您在Inventory 中是否真的有任何项目不在Subset 中? 解释查询应该返回什么。目前,它返回引用它的子集中没有产品的所有库存项目。 【参考方案1】:
SELECT foreignStockId
FROM   [Subset].[dbo].[Products]  

可能返回NULL

如果NOT IN 值列表中存在任何NULLs,NOT 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 才能返回行,但当 NULL 存在时,NOT IN 不可能,如下所述。

'A' NOT IN ('X','Y',NULL) 等价于'A' <> 'X' AND 'A' <> 'Y' AND 'A' <> NULL)

'A' 'X' = True 'A' 'Y' = True 'A' NULL = Unknown

True AND True AND Unknown 根据truth tables for three valued logic 计算为Unknown

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

Should I use NOT IN, OUTER APPLY, LEFT OUTER JOIN, EXCEPT, or NOT EXISTS? NOT IN vs. NOT EXISTS vs. LEFT JOIN / IS NULL: SQL Server Left outer join vs NOT EXISTS NOT EXISTS vs NOT IN

【讨论】:

这为我解决了问题。 Select * From x Where x.y not in(Select Distinct ISNULL(c,0)) 天哪,确实选择返回 null 并且 NOT IN 工作不正常。 6年后我向你致敬【参考方案2】:

如果 NOT IN 不起作用,您可以随时尝试 LEFT JOIN。然后使用连接表中的值之一(即 NULL)按 WHERE 进行过滤。前提是,您加入的值不包含任何 NULL 值。

【讨论】:

【参考方案3】:

加我的 2 美分:

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

【讨论】:

【参考方案4】:

您也可以使用 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

【讨论】:

以上是关于SQL NOT IN 不工作的主要内容,如果未能解决你的问题,请参考以下文章

sql [sql技巧]一些sql技巧#sql

SQL基础

有大神知道,sql server 中如何批量执行sql语句吗?

pl sql developer怎么执行sql

pl sql developer怎么执行sql

什么是sql注入如何防止sql注入