Не равно <>! = Оператор на NULL

271

Может кто-нибудь объяснить, пожалуйста, следующее поведение в SQL?

SELECT * FROM MyTable WHERE MyColumn != NULL (0 Results)
SELECT * FROM MyTable WHERE MyColumn <> NULL (0 Results)
SELECT * FROM MyTable WHERE MyColumn IS NOT NULL (568 Results)
Максим Гершкович
источник

Ответы:

309

<>Стандарт SQL-92; !=это его эквивалент. Оба оценивают значения, а NULLне - NULLэто заполнитель, чтобы сказать, что значение отсутствует.

Вот почему вы можете использовать IS NULL/ в IS NOT NULLкачестве предикатов только для таких ситуаций.

Это поведение не относится к SQL Server. Все совместимые со стандартами диалекты SQL работают одинаково.

Примечание . Для сравнения, если ваше значение не равно нулю , вы используете IS NOT NULL, а для сравнения - не нулевое значение <> 'YOUR_VALUE'. Я не могу сказать, равно или нет мое значение NULL, но я могу сказать, равно ли мое значение NULL или NOT NULL. Я могу сравнить, если мое значение отличается от NULL.

OMG пони
источник
4
На самом деле, я считаю, <>что это в спецификации 92, но большинство поставщиков поддерживают !=и / или она включена в более позднюю спецификацию, такую ​​как 99 или 03.
Томас
2
@Thomas: Oracle не поддерживал !=до ~ 9i, как я понимаю, что привело к большому синтаксису ANSI-92. Я верю, что MySQL похож, начиная поддержку в 4.x.
OMG Ponies
Казалось бы, можно предположить, что это !=могло быть включено в более позднюю спецификацию в качестве альтернативы <>. У меня нет новых спецификаций, поэтому я не могу сказать наверняка.
Томас
2
Является ли результат WHERE MyColumn != NULLили WHERE MyColumn = NULLдетерминированным? Или, другими словами, гарантированно всегда возвращать 0 строк, независимо от того MyColumn, обнуляется ли это в базе данных или нет?
Слаума
11
Следует также отметить, что, поскольку !=выполняется только оценка значений, выполнение чего-либо подобного WHERE MyColumn != 'somevalue'не будет возвращать записи NULL.
jsumrall
88

NULL не имеет значения и поэтому не может сравниваться с использованием операторов скалярного значения.

Другими словами, никакое значение не может быть равно (или не равно) NULL, потому что NULL не имеет значения.

Следовательно, SQL имеет специальные предикаты IS NULL и IS NOT NULL для работы с NULL.

Барри Браун
источник
3
+1. И, вопреки утверждению OP, это не «Microsoft SQL». Тройная логика определена в стандарте SQL, и MS в этом пункте придерживается стандарта.
TomTom
6
Я не предполагал, что это единственное поведение Microsoft. Я просто заявлял, что заметил это на Microsoft SQL Server.
Максим Гершкович
13
Из интереса, есть ли ситуации, когда это (ожидаемое) поведение полезно? Мне просто кажется, что 'a' != nullНЕ возвращать значение ( true/ 1) нелогично и время от времени меня ловит! Я бы подумал, что «какое-то значение по сравнению с отсутствием» всегда будет «не равным», но, может быть, это только я ?!
ДартПабло
1
Я думаю, что интересно, что люди описывают NULL как «не имеющие значения ». Аналогично тому, что число 1 «имеет значение», когда оно на самом деле является значением. Но NULL представляет не-ценность ..
systemaddict
В качестве ручного обходного пути вы можете обычно SELECT * FROM MyTable WHERE coalesce(MyColumn, 'x') <> 'x'назначать константу, если она имеет значение NULL, при условии, что вы предоставляете соответствующий тип данных для значения дозорного x (в данном случае строка / символ). Это синтаксис TSQL, но Oracle и другие движки имеют схожие функции.
Систематический приговор
26

Обратите внимание, что это поведение является поведением по умолчанию (ANSI).

Если ты:

 SET ANSI_NULLS OFF

http://msdn.microsoft.com/en-us/library/ms188048.aspx

Вы получите разные результаты.

SET ANSI_NULLS OFF видимо, уйду в будущем ...

Кейд Ру
источник
8
+1 ... не скоро. Теперь, когда я могу получить «дубликаты» NULL в индексе? :(
Вы можете получить дубликаты NULL в индексе SQL Server, добавив предложение WHERE в отфильтрованный индекс (например create unique index UK_MyTable on MyTable (Column) where Column is not null): msdn.microsoft.com/en-us/library/cc280372.aspx
Энтони Миллс
3
Примечание из документов: Когда SET ANSI_NULLSустановлено значение OFF, операторы сравнения Equals (=) и Not Equal To (<>) не соответствуют стандарту ISO. Оператор SELECT, который использует, WHERE column_name = NULLвозвращает строки с нулевыми значениями в column_name. Оператор SELECT, который использует, WHERE column_name <> NULLвозвращает строки, которые имеют ненулевые значения в столбце. Кроме того, оператор SELECT, который использует, WHERE column_name <> XYZ_valueвозвращает все строки, которые не являются XYZ_value и которые не равны NULL. ИМХО, это последнее утверждение кажется немного странным в том смысле, что оно исключает нули из результатов!
ДартПабло
4
Важное примечание из документа msdn : в будущей версии SQL Server [более новой, чем 2014 г.] ANSI_NULLS всегда будет включен, и любые приложения, явно установившие параметр в OFF, будут генерировать ошибку. Избегайте использования этой функции в новых разработках и планируйте модифицировать приложения, которые в настоящее время используют эту функцию.
Отиэль
7

В SQL все, что вы оцениваете / вычисляете с NULLрезультатами в НЕИЗВЕСТНО

Вот почему SELECT * FROM MyTable WHERE MyColumn != NULLили SELECT * FROM MyTable WHERE MyColumn <> NULLдает вам 0 результатов.

Для проверки NULLзначений предусмотрена функция isNull.

Кроме того, вы можете использовать ISоператор, как вы использовали в третьем запросе.

Надеюсь это поможет.

Махендра Лия
источник
«В SQL все, что вы вычисляете / вычисляете с результатами NULL в« NULL »» - неверно. Вы имеете в виду НЕИЗВЕСТНЫЙ результат.
onedaywhen
@MahendraLiya функция isNull не предназначена для проверки на NULLS, но она « заменяет NULL указанным значением замены. ». Вы должны использовать IS NULL или IS NOT NULL вместо ISNULL, что совсем другое.
Обратный инженер
7

Единственный тест для NULL - это NULL или не NULL. Проверка на равенство бессмысленна, потому что по определению никто не знает, что это такое.

Вот статья в Википедии для чтения:

https://en.wikipedia.org/wiki/Null_(SQL)

dkretz
источник
6

Мы используем

SELECT * FROM MyTable WHERE ISNULL(MyColumn, ' ') = ' ';

вернуть все строки, где MyColumn равен NULL, или все строки, где MyColumn является пустой строкой. Для многих «конечных пользователей» проблема пустых и пустых строк - это различие без необходимости и смысла.

Джефф Мерглер
источник
5

Я просто не вижу функциональной и плавной причины, по которой значения NULL не сопоставимы с другими значениями или другими значениями NULL, поскольку мы можем четко сравнить их и сказать, что они одинаковы или нет в нашем контексте. Это забавно. Просто из-за некоторых логических выводов и последовательности мы должны постоянно с этим беспокоиться. Это не функционально, сделайте его более функциональным и предоставьте философам и ученым возможность сделать вывод, является ли оно последовательным или нет и содержит ли оно «универсальную логику». :) Кто-то может сказать, что это из-за индексов или чего-то еще, я сомневаюсь, что эти вещи не могут поддерживать нулевые значения, такие же как значения. Это то же самое, что сравнивать два пустых стакана, один - бокал для вина, а другой - бокал для пива, мы не сравниваем типы объектов, а значения, которые они содержат, так же, как вы могли бы сравнить int и varchar, с нулем it ' Еще проще, ничего общего и ничего общего с двумя небытиями, они одинаковы, очевидно сопоставимы мной и всеми, кто пишет sql, потому что мы постоянно нарушаем эту логику, сравнивая их странным образом из-за некоторых стандартов ANSI. Почему бы не использовать компьютерную мощность, чтобы сделать это для нас, и я сомневаюсь, что это замедлило бы ситуацию, если бы все, что связано, строилось с учетом этого. «Это не ноль, это ничего», это не яблоко, это apfel, давай ... Функционально это твой друг, и здесь тоже есть логика. В конце концов, единственное, что имеет значение, - это функциональность, и использование нулей таким образом приносит более или менее функциональность и простоту использования. Это более полезно? потому что мы постоянно нарушаем эту логику, сравнивая их странным образом из-за некоторых стандартов ANSI. Почему бы не использовать компьютерную мощность, чтобы сделать это для нас, и я сомневаюсь, что это замедлило бы ситуацию, если бы все, что связано, строилось с учетом этого. «Это не ноль, это ничего», это не яблоко, это apfel, давай ... Функционально это твой друг, и здесь тоже есть логика. В конце концов, единственное, что имеет значение, - это функциональность, и использование нулей таким образом приносит более или менее функциональность и простоту использования. Это более полезно? потому что мы постоянно нарушаем эту логику, сравнивая их странным образом из-за некоторых стандартов ANSI. Почему бы не использовать компьютерную мощность, чтобы сделать это для нас, и я сомневаюсь, что это замедлило бы ситуацию, если бы все, что связано, строилось с учетом этого. «Это не ноль, это ничего», это не яблоко, это apfel, давай ... Функционально это твой друг, и здесь тоже есть логика. В конце концов, единственное, что имеет значение, - это функциональность, и использование нулей таким образом приносит более или менее функциональность и простоту использования. Это более полезно? не яблоко, это apfel, давай ... Функционально это твой друг, и здесь тоже есть логика. В конце концов, единственное, что имеет значение, - это функциональность, и использование нулей таким образом приносит более или менее функциональность и простоту использования. Это более полезно? не яблоко, это apfel, давай ... Функционально это твой друг, и здесь тоже есть логика. В конце концов, единственное, что имеет значение, - это функциональность, и использование нулей таким образом приносит более или менее функциональность и простоту использования. Это более полезно?

Рассмотрим этот код:

SELECT CASE WHEN NOT (1 = null or (1 is null and null is null)) THEN 1 ELSE 0 end

Кто из вас знает, что вернет этот код? С или без НЕТ возвращает 0. Для меня это не функционально и сбивает с толку. В c # это все, как и должно быть, операции сравнения возвращают значение, логически это тоже создает значение, потому что если нет, сравнивать нечего (кроме. :)). Они просто «сказали»: все, что равно нулю, «возвращает» 0, и это создает много обходных путей и головных болей.

Это код, который привел меня сюда:

where a != b OR (a is null and b IS not null) OR (a IS not null and b IS null)

Мне просто нужно сравнить, если два поля (где) имеют разные значения, я мог бы использовать функцию, но ...

Хрвое Батрнек
источник
4

NULL Невозможно сравнить с любым значением с помощью операторов сравнения. NULL = NULL является ложным. Нуль не является значением. Оператор IS специально разработан для обработки пустых сравнений.

Винсент Рамдхани
источник
5
Мне всегда нравились смущенные люди, когда я иногда использую null = nullто, что можно использовать 1=0в каком-то специальном запросе. И если они жалуются, я изменяю это на null != null:)
SWeko
8
«NULL = NULL - ложь» Это не так. NULL = NULL оценивается как неизвестное и не ложное.
nvogel
@dportas это так, но я имел в виду, что в условном выражении оно не будет оцениваться как истинное.
Винсент Рамдани
@VincentRamdhanie ни как ложный; на самом деле, в postgres он будет оцениваться как NULL
Pere
2

Старый вопрос, но следующий может предложить более подробную информацию.

nullне представляет значение или неизвестное значение. В нем не указано, почему нет значения, что может привести к некоторой неопределенности.

Предположим, вы запустили такой запрос:

SELECT *
FROM orders
WHERE delivered=ordered;

то есть вы ищете строки, где orderedи deliveredдаты совпадают.

Чего ожидать, если один или оба столбца равны нулю?

Поскольку хотя бы одна из дат неизвестна, нельзя ожидать, что эти две даты совпадают. Это также тот случай, когда обе даты неизвестны: как они могут быть одинаковыми, если мы даже не знаем, какие они есть?

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

SELECT *
FROM orders
WHERE delivered<>ordered;

Опять же, как мы можем сказать, что два значения не одинаковы, если мы не знаем, что это такое.

SQL имеет специальный тест для пропущенных значений:

IS NULL

В частности, он не сравнивает значения, а скорее ищет пропущенные значения.

Наконец, что касается !=оператора, насколько мне известно, его нет ни в одном из стандартов, но он очень широко поддерживается. Он был добавлен, чтобы программисты из некоторых языков чувствовали себя как дома. Честно говоря, если программисту трудно вспомнить, какой язык он использует, у него плохое начало.

Manngo
источник
Это та же самая «бессмысленная» «логика», которую @Hove описывает в своем ответе. Правда в том, что в этом контексте нет необходимости в этих дополнительных атрибутах; можно легко предположить, что когда мы сравниваем что-то с a, NULLмы имеем в виду, что мы сравниваем значение с «имеющим NULLзначение», а не с «неопределенным значением, которое есть в основе» NULL, но что мы не знаем ", который, очевидно, мы не сможем когда-либо знать. Это действительно облегчило бы ситуацию.
Пере
@Prere Я бы не сказал, что это строго «бессмысленно», и я не уверен, что писать IS NULLгораздо сложнее, чем писать = NULL. Я думаю, что было бы более последовательным, если бы WHERE columnA = columnBимел такую ​​же интерпретацию WHERE columnA = NULL, а не рассматривать последний как особый случай. Помните, что NULLэто не ценность. В языках программирования , где он является законным , чтобы проверить variable == nullэто , потому что nullимеет другое значение; это не представляет что-то неизвестное, но преднамеренное восстановление значения. Не так с SQL.
Manngo
Вот почему я поместил его в кавычки, @Mangoo;) (а также «логика»). Не сердись на меня; Я говорил о «рассуждениях» ANSI, а не о вашем объяснении. Я согласен с тем, что в вашем последнем примере нет накладных расходов между IS NULLAND =NULL. Но взгляните на последний Ховер. Я устал испытывать это снова и снова, делая ненужные нагрузки? дополнительная проверка ...
Пере
1

Я хотел бы предложить этот код, который я сделал, чтобы найти, есть ли изменение в значении, iявляющемся новым значением и dявляющимся старым (хотя порядок не имеет значения). В этом отношении изменение от значения к нулю или наоборот является изменением, но от нуля к нулю не является (конечно, от значения к другому значению является изменение, но от значения к тому же самому это не так).

CREATE FUNCTION [dbo].[ufn_equal_with_nulls]
(
    @i sql_variant,
    @d sql_variant
)
RETURNS bit
AS
BEGIN
    DECLARE @in bit = 0, @dn bit = 0
    if @i is null set @in = 1
    if @d is null set @dn = 1

    if @in <> @dn
        return 0

    if @in = 1 and @dn = 1
        return 1

    if @in = 0 and @dn = 0 and @i = @d
        return 1

    return 0

END

Чтобы использовать эту функцию, вы можете

declare @tmp table (a int, b int)
insert into @tmp values
(1,1),
(1,2),
(1,null),
(null,1),
(null,null)

---- in select ----
select *, [dbo].[ufn_equal_with_nulls](a,b) as [=] from @tmp

---- where equal ----
select *,'equal' as [Predicate] from @tmp where  [dbo].[ufn_equal_with_nulls](a,b) = 1

---- where not equal ----
select *,'not equal' as [Predicate] from @tmp where  [dbo].[ufn_equal_with_nulls](a,b) = 0

Результаты:

---- in select ----
a   b   =
1   1   1
1   2   0
1   NULL    0
NULL    1   0
NULL    NULL    1

---- where equal ----
1   1   equal
NULL    NULL    equal

---- where not equal ----
1   2   not equal
1   NULL    not equal
NULL    1   not equal

Использование sql_variant делает его совместимым для различных типов

Ярив де Боттон
источник
0

NULL это не что-нибудь ... это неизвестно. NULL не равняется ничему. Вот почему вы должны использовать волшебную фразу IS NULL вместо = NULL в ваших SQL-запросах.

Вы можете сослаться на это: http://weblogs.sqlteam.com/markc/archive/2009/06/08/60929.aspx

Тень
источник