"<>" против "НЕ В" - PullRequest
       10

"<>" против "НЕ В"

20 голосов
/ 13 мая 2009

Я отлаживал хранимую процедуру на днях и нашел что-то вроде логики:

SELECT something
FROM someTable
WHERE idcode <> (SELECT ids FROM tmpIdTable)

Это ничего не вернуло. Я думал, что это выглядело немного странно с «<>», поэтому я изменил его на «НЕ В», и тогда все работало нормально. Мне было интересно, почему это? Это довольно старый процесс, и я не совсем уверен, как долго эта проблема существовала, но мы недавно переключились с SQL Server 2005 на SQL Server 2008, когда это было обнаружено. Какова реальная разница между "<>" и "NOT IN" и изменилось ли поведение между Server2005 и 2008?

Ответы [ 8 ]

20 голосов
/ 13 мая 2009
SELECT something
FROM someTable
WHERE idcode NOT IN (SELECT ids FROM tmpIdTable)

проверяет любое значение в списке.

Однако NOT IN не является пустым. Если подзапрос возвратил набор значений, содержащих NULL, никакие записи не будут возвращены вообще. (Это потому, что внутренне NOT IN оптимизирован до idcode <> 'foo' AND idcode <> 'bar' AND idcode <> NULL и т. Д., Что всегда будет неудачным, потому что любое сравнение с NULL приводит к UNKNOWN, предотвращая превращение целого выражения в TRUE.)

Более хороший, NULL-толерантный вариант будет следующим:

SELECT something
FROM someTable
WHERE NOT EXISTS (SELECT ids FROM tmpIdTable WHERE ids = someTable.idcode)

РЕДАКТИРОВАТЬ: я изначально предполагал, что это:

SELECT something
FROM someTable
WHERE idcode <> (SELECT ids FROM tmpIdTable)

будет проверять только первое значение. Оказывается, это предположение неверно, по крайней мере, для SQL Server, где оно фактически вызывает его ошибку:

Msg 512, Level 16, State 1, Line 1
Subquery returned more than 1 value. This is not permitted when the subquery follows =, !=, <, <= , >, >= or when the subquery is used as an expression.
13 голосов
/ 13 мая 2009

попробуйте, может работать быстрее из-за использования индекса:

SELECT something
FROM someTable
    LEFT OUTER JOIN tmpIdTable ON idcode=ids
WHERE ids IS NULL
8 голосов
/ 13 мая 2009

<> является «единственной» NOT операцией; NOT IN - это заданная операция, поэтому имеет смысл, что первая не будет работать. Однако я понятия не имею, могло ли это быть сделано в предыдущей версии SQL Server.

5 голосов
/ 13 мая 2009

Этот код действителен тогда и только тогда, когда из tmpIdTable не найдено ни одной строки или единственной строки:

SELECT something
FROM someTable
WHERE idcode <> (SELECT ids FROM tmpIdTable)

Если будет возвращено несколько строк, вы получите сообщение об ошибке:

Сообщение 512, Уровень 16, Состояние 1, Строка 1 Подзапрос вернул более 1 значения. Это недопустимо, если подзапрос следует =,! =, <, <=,>,> = Или когда подзапрос используется в качестве выражения.

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

ВЫБРАТЬ *, (ВЫБРАТЬ БЛА ОТ t1 ГДЕ и т. Д.) ОТ t2

Ничто не изменило WRT в SQL Server за десятилетие, поэтому я ожидаю, что предположения о вложенном запросе в исходном коде были нарушены.

Если строки не возвращаются, результат будет пустым, поскольку <> NULL никогда не имеет значения true (предположим, ANSI NULL).

Этот код действителен для любого количества строк:

SELECT something
FROM someTable
WHERE idcode NOT IN (SELECT ids FROM tmpIdTable)

Тем не менее, могут быть проблемы с NULL.

3 голосов
/ 13 мая 2009

Если подзапрос SELECT возвращает ноль строк, это NULL. Когда NULL сравнивается с чем-либо, результат всегда НЕИЗВЕСТЕН ​​и никогда не ИСТИНА. Как ни странно, NOT UNKNOWN равно UNKNOWN.

Я избегаю трехзначной логики (ИСТИНА, ЛОЖЬ, НЕИЗВЕСТНО), когда это возможно. Это не так сложно избежать, как только вы овладеете им.

Если подзапрос SELECT возвращает ровно одно значение, сравнение неравенства должно вернуть ожидаемый результат.

Если подзапрос SELECT возвращает более одного значения, вы должны получить ошибку.

Как правило, NOT IN возвращает ожидаемый результат при тестировании на отсутствие членства в наборе.

Этот ответ перекрывает другие ответы, но он сформулирован немного по-другому.

Отредактировано, чтобы добавить более подробную информацию о NOT IN:

Я кое-что искал по поводу НЕ В в Oracle и узнал кое-что, чего не знал полчаса назад. NOT IN не имеет значения NULL. В частности,

X NOT IN (SELECT ...)

Это не то же самое, что

NOT (X IN SELECT ...))

Возможно, мне придется изменить мой предыдущий ответ!

3 голосов
/ 13 мая 2009

Понятия не имею, зачем вы пишете что-то вроде WHERE idcode <> (SELECT ids FROM tmpIdTable). Оператор SELECT возвращает набор кортежей, и ваш idcode либо будет, либо НЕ будет В этом наборе. «WHERE idcode NOT IN (SELECT ids FROM tmpIdTable)» - это способ сделать это.

2 голосов
/ 19 мая 2009

запросов с использованием NOT IN могут быть хрупкими:

http://sqlblog.com/blogs/alexander_kuznetsov/archive/2008/10/21/defensive-database-programming-rewriting-queries-with-not-in.aspx

0 голосов
/ 13 мая 2009

в некоторых версиях SQL ! = следует использовать для логического утверждения "не равно". Вы пробовали это?

...