这些是相当基本的声明。我有一个图形列表,这些图形链接到另一个表中的项目。我要检查有多少个图形未使用并且理论上可以删除。
所以首先我使用了NOT IN子句:
SELECT [GraphicNr]
,[Graphicfile]
FROM [dbo].[Graphic]
WHERE graphicnr NOT IN (SELECT graphicnr FROM dbo.Komp)
哪个给出零结果,这对我来说似乎很奇怪。将其重写为“不存在”后,我得到了大约600个结果:
SELECT [GraphicNr]
,[Graphicfile]
FROM [dbo].[Graphic] a
WHERE NOT EXISTS (SELECT graphicnr FROM dbo.komp b WHERE a.GraphicNr = b.GraphicNr)
所以我想我真的没有问题,因为第二个语句有效,但是据我所知,第一个语句不应该给出相同的结果吗?
答案 0 :(得分:3)
NOT IN
行为异常。如果子查询中的任何行返回一个NULL
值,则返回 no 行。这是由于遵循NULL
的严格语义(这意味着:“我不知道它们是否相等”)。
NOT EXISTS
的行为符合您的预期。因此,建议不要将NOT IN
与子查询一起使用。始终使用NOT EXISTS
。
答案 1 :(得分:0)
由于NULL
返回了subquery
值:
SELECT [GraphicNr], [Graphicfile]
FROM [dbo].[Graphic]
WHERE graphicnr NOT IN (SELECT graphicnr FROM dbo.Komp)
由于no records
,这将产生no rows affected
或graphicnr not in (null)
,这不是期望的输出。
因此,NOT EXISTS
不能像IN
子句或NOT IN
那样工作。它的行为与IN
或NOT IN
子句不同。
但是,您可以通过使用IS NOT NULL
中的subquery
过滤器来防止这种情况。但是建议的方法是改用NOT EXISTS
。
答案 2 :(得分:0)
此查询产生预期的结果:
SELECT *
FROM (SELECT 1 UNION ALL SELECT 2) AS tbl(col)
WHERE col IN (NULL, 1)
-- returns first row
但是添加NOT
不会反转结果:
SELECT *
FROM (SELECT 1 UNION ALL SELECT 2) AS tbl(col)
WHERE NOT col IN (NULL, 1)
-- returns zero rows
这是因为上面的查询大致等同于以下内容:
SELECT *
FROM (SELECT 1 UNION ALL SELECT 2) AS tbl(col)
WHERE NOT (col = NULL OR col = 1)
这是where子句的计算方式:
| col | col = NULL (1) | col = 1 | col = NULL OR col = 1 | NOT (col = NULL OR col = 1) |
|-----|----------------|---------|-----------------------|-----------------------------|
| 1 | UNKNOWN | TRUE | TRUE | FALSE |
| 2 | UNKNOWN | FALSE | UNKNOWN (2) | UNKNOWN (3) |
注意:
您可以将上面的示例扩展为两个以上的值(例如NULL,1和2),但结果将是相同的:如果其中一个值为NULL
,则没有行会匹配。
TLDR:基本上可以归结为SQL中使用的三值逻辑。要征服SQL,您需要掌握它。如果不能,则遵循 使用NOT EXISTS
的建议。