Эта проблема возникла, когда я получил различное количество записей для идентичных запросов, один из которых использовал not in
where
ограничение, а другой a left join
. Таблица в not in
ограничении имела одно нулевое значение (неверные данные), в результате чего этот запрос возвращал количество записей 0. Я вроде понимаю почему, но я мог бы использовать некоторую помощь, чтобы полностью понять концепцию.
Проще говоря, почему запрос A возвращает результат, а B нет?
A: select 'true' where 3 in (1, 2, 3, null)
B: select 'true' where 3 not in (1, 2, null)
Это было на SQL Server 2005. Я также обнаружил, что при вызове set ansi_nulls off
B возвращает результат.
NOT IN
в серию<> and
изменений меняет семантическое поведение не в этом наборе на что-то еще?SELECT 1 WHERE NULL NOT IN (SELECT 1 WHERE 1=0);
выдает строку вместо пустого набора результатов, который я ожидал.Всякий раз, когда вы используете NULL, вы действительно имеете дело с трехзначной логикой.
Ваш первый запрос возвращает результаты, поскольку предложение WHERE оценивается как:
Второй:
UNKNOWN - это не то же самое, что FALSE, вы можете легко проверить это, вызвав:
Оба запроса не дадут вам результатов
Если UNKNOWN был таким же, как FALSE, то при условии, что первый запрос даст вам FALSE, второй должен будет иметь значение TRUE, поскольку оно будет таким же, как NOT (FALSE).
Это не относится к делу.
На SqlServerCentral есть очень хорошая статья на эту тему .
Поначалу проблема NULL и трехзначной логики может немного сбивать с толку, но это важно понять, чтобы писать правильные запросы в TSQL.
Другая статья, которую я бы порекомендовал, - это Агрегатные функции SQL и NULL .
источник
NOT IN
возвращает 0 записей при сравнении с неизвестным значениемПоскольку
NULL
неизвестен,NOT IN
запрос, содержащий aNULL
илиNULL
s в списке возможных значений, всегда будет возвращать0
записи, поскольку нет никакого способа убедиться, что этоNULL
значение не является проверяемым значением.источник
Сравнение с нулем не определено, если вы не используете IS NULL.
Таким образом, при сравнении 3 с NULL (запрос A) возвращается неопределенное значение.
Т.е. ВЫБРАТЬ «истина», где 3 в (1,2, ноль) и ВЫБРАТЬ «истина», где 3 не в (1,2, ноль)
выдаст тот же результат, так как NOT (UNDEFINED) по-прежнему не определен, но не TRUE
источник
Название этого вопроса на момент написания
Из текста вопроса видно, что проблема возникла в
SELECT
запросе SQL DML , а не в DDL SQLCONSTRAINT
.Однако, особенно учитывая формулировку заголовка, я хочу отметить, что некоторые высказанные здесь заявления являются потенциально вводящими в заблуждение утверждениями, аналогичными (перефразируя)
Хотя это относится к SQL DML, при рассмотрении ограничений эффект будет другим.
Рассмотрим эту очень простую таблицу с двумя ограничениями, взятыми непосредственно из предикатов в вопросе (и адресованных в превосходном ответе @Brannon):
Согласно ответу @ Brannon, первое ограничение (using
IN
) оценивается как TRUE, а второе ограничение (usingNOT IN
) - UNKNOWN. Тем не менее , вставка удалась! Следовательно, в этом случае не совсем правильно говорить «вы не получаете никаких строк», потому что мы действительно вставили строку в результате.Вышеуказанный эффект действительно правильный в отношении стандарта SQL-92. Сравните и сопоставьте следующий раздел из спецификации SQL-92
Другими словами:
В SQL DML строки удаляются из результата, когда
WHERE
вычисляется как UNKNOWN, поскольку он не удовлетворяет условию «true».В SQL DDL (т.е. ограничение), строки не удаляются из результата , когда они оценивают Неизвестный , потому что это действительно удовлетворяет условие «не является ложным».
Хотя эффекты в SQL DML и SQL DDL соответственно могут показаться противоречивыми, существует практическая причина для того, чтобы дать НЕИЗВЕСТНЫМ результатам «преимущество сомнения», позволяя им удовлетворять ограничению (более правильно, позволяя им не отказывать в удовлетворении ограничения) без этого поведения все ограничения должны были бы явно обрабатывать нули, и это было бы очень неудовлетворительно с точки зрения языкового дизайна (не говоря уже о том, что кодерам было бы больно!)
ps, если вам кажется сложным следовать такой логике, как «неизвестный не нарушает ограничение», как я это написал, то подумайте, что вы можете обойтись без всего этого, просто избегая пустых столбцов в SQL DDL и всего в SQL DML, который производит нули (например, внешние соединения)!
источник
NOT IN (subquery)
использование нулей может дать неожиданные результаты, заманчиво избегатьIN (subquery)
полностью и всегда использоватьNOT EXISTS (subquery)
(как я когда-то делал!), Потому что кажется, что оно всегда обрабатывает нулевые значения правильно. Однако есть случаи, когдаNOT IN (subquery)
дает ожидаемый результат, тогда какNOT EXISTS (subquery)
дает неожиданные результаты! Я могу найти время, чтобы написать это, если смогу найти свои заметки на эту тему (нужны заметки, потому что это не интуитивно понятно!) Вывод тот же: избегайте нулей!TRUE
,FALSE
иUNKNOWN
. Я полагаю, что 4.10 мог бы прочитать: «Ограничение проверки таблицы выполняется тогда и только тогда, когда указанное условие поиска равно TRUE или UNKNOWN для каждой строки таблицы», - обратите внимание на мое изменение в конце предложения, которое вы пропустили. - от «для любого» до «для всех„Я чувствую необходимость капитализировать логические значения , так как смысл. „истина“ и „ложь“ на естественном языке , должны , безусловно , относится к классической двузначной логике.CREATE TABLE T ( a INT NOT NULL UNIQUE, b INT CHECK( a = b ) );
- намерение здесьb
должно быть равнымa
или равным нулю. Если ограничение должно было приводить к TRUE, чтобы быть удовлетворенным, тогда нам нужно изменить ограничение, чтобы явно обрабатывать нули, напримерCHECK( a = b OR b IS NULL )
. Таким образом, каждое ограничение должно иметь...OR IS NULL
добавленную пользователем логику для каждого включаемого столбца: больше сложности, больше ошибок, когда они забыли это сделать и т. Д. Поэтому я думаю, что комитет по стандартам SQL просто пытался быть прагматичным.В А 3 проверяется на равенство по отношению к каждому члену множества, уступая (ЛОЖЬ, ЛОЖЬ, ИСТИНА, НЕИЗВЕСТНО). Поскольку один из элементов имеет значение ИСТИНА, условие ИСТИНА. (Также возможно, что здесь происходит некоторое короткое замыкание, поэтому оно фактически останавливается, как только достигает первого ИСТИНА и никогда не оценивает 3 = NULL.)
В B, я думаю, это оценивает условие как НЕ (3 в (1,2, ноль)). Тестирование 3 на равенство с заданным выходом (FALSE, FALSE, UNKNOWN), которое агрегируется в UNKNOWN. НЕ (НЕИЗВЕСТНО) приводит к НЕИЗВЕСТНО. Таким образом, в целом истинность условия неизвестна, что в конце концов рассматривается как ЛОЖЬ.
источник
Из приведенных здесь ответов можно сделать вывод, что
NOT IN (subquery)
неправильно обрабатывает нули и его следует избегать в пользуNOT EXISTS
. Однако такой вывод может быть преждевременным. В следующем сценарии, зачисленном Крису Дейту (Программирование баз данных и проектирование, Том 2, № 9, сентябрь 1989 г.), онNOT IN
обрабатывает пустые значения правильно и возвращает правильный результат, а неNOT EXISTS
.Рассмотрим таблицу
sp
для представления поставщиков (sno
), которые, как известно, поставляют запчасти (pno
) в количестве (qty
). В настоящее время таблица содержит следующие значения:Обратите внимание, что количество можно обнулять, т. Е. Иметь возможность зафиксировать тот факт, что поставщик, как известно, поставляет детали, даже если неизвестно, в каком количестве.
Задача состоит в том, чтобы найти поставщиков, которые известны под номером поставки P1, но не в количестве 1000.
Следующие варианты используются только
NOT IN
для правильной идентификации поставщика «S2»:Однако в приведенном ниже запросе используется та же общая структура, но с
NOT EXISTS
неверным включением в результат поставщика «S1» (т. Е. Для которого значение равно нулю):Так
NOT EXISTS
не серебряная пуля, это, возможно, появилось!Конечно, источником проблемы является наличие нулей, поэтому «реальным» решением является устранение этих нулей.
Это может быть достигнуто (среди других возможных конструкций) с использованием двух таблиц:
sp
поставщики, как известно, поставляют запчастиspq
известные поставщики поставляют запчасти в известных количествахотмечая, что должно быть ограничение внешнего ключа, где
spq
ссылкиsp
.Затем результат можно получить с помощью реляционного оператора «минус» (который является
EXCEPT
ключевым словом в стандартном SQL), напримеристочник
Нуль означает и отсутствие данных, то есть оно неизвестно, а не значение данных ничего. Людям, имеющим опыт программирования, очень легко запутать это, поскольку в языках типов C при использовании указателей null действительно ничего не значит.
Следовательно, в первом случае 3 действительно находится во множестве (1,2,3, null), поэтому возвращается true
Во втором, однако, вы можете уменьшить его до
выберите «истина», где 3 не в (ноль)
Таким образом, ничего не возвращается, потому что анализатор ничего не знает о наборе, с которым вы сравниваете его - это не пустой набор, а неизвестный набор. Использование (1, 2, null) не помогает, потому что набор (1,2), очевидно, ложен, но тогда вы и делаете это против неизвестного, что неизвестно.
источник
Если вы хотите отфильтровать с NOT IN для подзапроса, связанного с NULL, просто отметьте для not null
источник
это для мальчика
это работает независимо от настроек ANSI
источник
SQL использует трехзначную логику для значений истинности.
IN
Запрос выдает ожидаемый результат:Но добавление
NOT
не инвертирует результаты:Это потому, что приведенный выше запрос эквивалентен следующему:
Вот как оценивается предложение where:
Заметь:
NULL
учетом урожайностиUNKNOWN
OR
Выражение , где ни один из операндов не являютсяTRUE
и по крайней мере один из операндов имеетUNKNOWN
выходыUNKNOWN
( исх )NOT
ИзUNKNOWN
выходовUNKNOWN
( исх )Вы можете расширить приведенный выше пример более чем на два значения (например, NULL, 1 и 2), но результат будет таким же: если одно из значений будет равно,
NULL
ни одна строка не будет соответствовать.источник
также это может быть полезно, чтобы узнать логическую разницу между объединением, существует и в http://weblogs.sqlteam.com/mladenp/archive/2007/05/18/60210.aspx
источник