Почему эти операторы SQL приводят к разным выводам? - PullRequest
0 голосов
/ 27 августа 2018

Это довольно основные утверждения. У меня есть список графики, которые связаны с элементами в другой таблице. Я хочу проверить, сколько графических объектов не используется и теоретически может быть удалено.

Итак, сначала я использовал предложение NOT IN:

SELECT [GraphicNr]
      ,[Graphicfile]
  FROM [dbo].[Graphic]
 WHERE graphicnr NOT IN (SELECT graphicnr FROM dbo.Komp)

Который дал ноль результатов, что показалось мне странным. Переписав его в NOT EXISTS, я получил около 600 результатов:

SELECT [GraphicNr]
      ,[Graphicfile]
  FROM [dbo].[Graphic] a
 WHERE NOT EXISTS (SELECT graphicnr FROM dbo.komp b WHERE a.GraphicNr = b.GraphicNr)

Так что, думаю, у меня действительно нет проблем, так как второе утверждение работает, но, насколько я понимаю, не должно ли первое дать те же результаты?

Ответы [ 3 ]

0 голосов
/ 27 августа 2018

Это из-за 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.

0 голосов
/ 27 августа 2018

Этот запрос дает ожидаемый результат:

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, дает UNKNOWN ( ref )
  3. NOT из UNKNOWN дает UNKNOWN ( ref )

Вы можете расширить приведенный выше пример более чем на два значения (например, NULL, 1 и 2), но результат будет таким же: если одно из значений равно NULL, то ни одна строка не будет соответствовать.

TLDR: все сводится к трехзначной логике, используемой в SQL. Чтобы победить SQL, вам нужно освоить его. Если вы не можете, просто следуйте совету , используйте NOT EXISTS.

0 голосов
/ 27 августа 2018

NOT IN с подзапросом имеет странное поведение. Если какая-либо строка в подзапросе возвращает значение NULL, то нет строк. Это связано с соблюдением строгой семантики NULL (что означает: «Я не знаю, равны ли они»).

NOT EXISTS ведет себя так, как вы ожидаете. По этой причине я рекомендую никогда не использовать NOT IN с подзапросом. Всегда используйте NOT EXISTS.

...