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
值列表中存在任何NULL
s,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。谓词可以评估为True
、False
或Unknown
。
WHERE
子句的计算结果必须为 True
才能返回行,但当 NULL
存在时,NOT IN
不可能,如下所述。
'A' NOT IN ('X','Y',NULL)
等价于'A' <> 'X' AND 'A' <> 'Y' AND 'A' <> NULL)
True
'A' 'Y' = True
'A' NULL = Unknown
True AND True AND Unknown
根据truth tables for three valued logic 计算为Unknown
。
以下链接对各种选项的性能进行了一些额外的讨论。
Should I useNOT 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 exists
和 left 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 不工作的主要内容,如果未能解决你的问题,请参考以下文章