Подтвердить что ты не робот

"<>" против "NOT IN"

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

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

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

4b9b3361

Ответ 1

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

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

Однако NOT IN не является NULL-толерантным. Если в подзапросе возвращен набор значений, содержащий 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)

EDIT: Первоначально предполагалось, что это:

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.

Ответ 2

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

SELECT something
FROM someTable
    LEFT OUTER JOIN tmpIdTable ON idcode=ids
WHERE ids IS NULL

Ответ 3

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

Ответ 4

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

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

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

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

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

SELECT *, (SELECT blah FROM t1 WHERE и т.д.) FROM t2

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

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

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

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

Однако все еще могут быть проблемы с NULL.

Ответ 5

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

Ответ 6

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

Я избегаю трехзначной логики (TRUE, FALSE, UNKNOWN), когда это возможно. Это не так сложно избежать, как только вы его повесите.

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

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

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

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

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

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

X NOT IN (SELECT ...)

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

NOT (X IN SELECT ...))

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

Ответ 8

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