为什么这些SQL语句导致不同的输出?

时间:2018-08-27 12:14:35

标签: sql sql-server tsql three-valued-logic

这些是相当基本的声明。我有一个图形列表,这些图形链接到另一个表中的项目。我要检查有多少个图形未使用并且理论上可以删除。

所以首先我使用了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)

所以我想我真的没有问题,因为第二个语句有效,但是据我所知,第一个语句不应该给出相同的结果吗?

3 个答案:

答案 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 affectedgraphicnr not in (null),这不是期望的输出。

因此,NOT EXISTS不能像IN子句或NOT IN那样工作。它的行为与INNOT 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)                 |

注意:

  1. 涉及NULL的比较产生UNKNOWN
  2. OR表达式中,所有操作数都不为TRUE,至少一个操作数为UNKNOWN会产生UNKNOWNref
  3. NOT中的UNKNOWN产生UNKNOWNref

您可以将上面的示例扩展为两个以上的值(例如NULL,1和2),但结果将是相同的:如果其中一个值为NULL,则没有行会匹配。

TLDR:基本上可以归结为SQL中使用的三值逻辑。要征服SQL,您需要掌握它。如果不能,则遵循 使用NOT EXISTS 的建议。