T-SQL: что НЕ (1=NULL)?
Я не получаю простую булеву алгебру на моем sql-сервере. Согласно msdn, следующий оператор должен возвращать "1", но на моем сервере он возвращает "0". Вы можете мне помочь?
SET ANSI_NULLS ON
SELECT CASE WHEN NOT(1=NULL) THEN 1 ELSE 0 END
Пожалуйста, посмотрите на MSDN. Там ясно сказано: "Сравнение NULL со значением, отличным от NULL, всегда приводит к FALSE". - независимо от того, что параметр ANSI_NULLS. Таким образом, "1=NULL" должно быть ЛОЖЬ, а NOT(FALSE) должно быть ИСТИНА, а оператор должен возвращать "1".
Но на моей машине он возвращает "0"!
Одним из объяснений может быть то, что "1=NULL" оценивается как "НЕИЗВЕСТНО". NOT(UNKNOWN) по-прежнему UNKNOWN ( msdn), что приведет к принудительному применению оператора CASE в ELSE.
Но тогда официальная документация оператора equals будет неправильной. Я не могу в это поверить!
Кто-нибудь может объяснить это поведение?
Большое спасибо за любую помощь!
Изменить (2012-03-15):
Я обнаружил одну вещь, которая может заинтересовать некоторых из вас:
CREATE TABLE #FooTest (Value INT)
ALTER TABLE #FooTest WITH CHECK ADD CONSTRAINT ccFooTestValue CHECK (Value>1)
PRINT '(NULL>1) = ' + CASE WHEN NULL>1 THEN 'True' ELSE 'False' END
INSERT INTO #FooTest (Value) VALUES (NULL)
Оператор печати пишет "False", но вставка выполняется без ошибок. SQL-Server, по-видимому, отрицает проверку-ограничение, чтобы искать строки, которые не выполняют проверку-ограничение:
IF EXISTS (SELECT * FROM inserted WHERE NOT(Value>NULL)) <Generate error>
Поскольку проверочное ограничение оценивается как UNKNOWN, отрицание также UNKNOWN, и SqlServer не находит ни одной строки, нарушающей проверочное ограничение.
7 ответов
Страница MSDN для "Равных", на которую вы ссылаетесь, определенно неверна.
Проверьте страницу MSDN для SET ANSI_NULLS.
Когда SET ANSI_NULLS включен, все сравнения с нулевым значением оцениваются как UNKNOWN.
Чтобы заставить этот пример оператора SQL работать должным образом, вы должны использовать сравнение, используя "IS NULL" или "IS NOT NULL" вместо использования оператора равенства (=). Например:
SELECT CASE WHEN NOT(1 IS NULL) THEN 1 ELSE 0 END
ИЛИ ЖЕ
SELECT CASE WHEN (1 IS NOT NULL) THEN 1 ELSE 0 END
Да, эта ссылка неверна. Подайте документацию об ошибке в Microsoft Connect.
Sql использует трехзначную логику, а не булеву логику. true
, false
, а также unknown
Большинство операторов сравнения (т.е. исключая IS [NOT] NULL
) с участием NULL
результат в unknown
не True
или же False
, Отрицание неизвестного дает неизвестное в соответствии с таблицами истинности, показанными здесь.
Это не булева логика, это трина логика: {Правда, Ложь, я не знаю.} Разбейте это следующим образом:
IF 1=NULL
print 'True'
else
print 'False'
Формирует False
так как 1=NULL
равняется NULL
ака "не правда"
IF not(1=NULL)
print 'True'
else
print 'False'
Также генерирует False
так как not(1=NULL)
равняется not(NULL)
равняется NULL
ака "не правда". Это заставляет вас
SELECT CASE WHEN NOT(1=NULL) THEN 1 ELSE 0 END
который, как указано выше, такой же, как
SELECT CASE WHEN NULL THEN 1 ELSE 0 END
который, так как NULL
не соответствует действительности, ELSE
пункт.
Короче говоря, насколько я понимаю, документация неверна. Удручает, но не уникально, и поэтому не совсем удивительно.
Вы хотите прочитать документацию поANSI_NULLS
, SQL фактически реализует троичную логику, а не булеву логику, где операция сравнения может привести к true, false или undefined. По сути, это означает, что приведенные вами объяснения верны.
Это можно продемонстрировать с помощью следующего запроса:
SET ANSI_NULLS ON
SELECT CASE
WHEN (1=NULL) THEN 0
WHEN NOT(1=NULL) THEN 1
ELSE -1
END
Что приводит к -1
на моей машине (SQL Server 2005 Enterprise). Изменение первой строки на SET ANSI_NULLS OFF
производит 1
как и ожидалось.
Итак, официальная документация неверна? Я бы сказал, что это вводит в заблуждение. Это говорит о том, что это приводит к ложному. Очевидно, это неправильно. Документация подразумевает, что сравнение ненулевого значения с NULL всегда приводит к несоответствию, значение которого также зависит от ANSI_NULLS
,
Конечно, на SQL Server 2012ANSI_NULLS
настройка была удалена, и поэтому ее установка в любом случае не изменит результат.
1=NULL, по-видимому, возвращает FALSE, только когда ANSI_NULLS выключен. В противном случае это неопределенно. Страница msdn, вероятно, должна быть отредактирована, чтобы прояснить этот момент.
SET ANSI_NULLS OFF
SELECT CASE WHEN (1=NULL) THEN 'true' ELSE 'false or unknown' END --returns false or unknown
, CASE WHEN NOT(1=NULL) THEN 'true' ELSE 'false or unknown' END --returns true
go
SET ANSI_NULLS ON
SELECT CASE WHEN (1=NULL) THEN 'true' ELSE 'false or unknown' END --returns false or unknown
, CASE WHEN NOT(1=NULL) THEN 'true' ELSE 'false or unknown' END --returns false or unknown
go
От BOL (кредит Томасу):
SET ANSI_NULLS ON влияет на сравнение, только если один из операндов сравнения является либо переменной, равной NULL, либо литералом NULL. Если обе стороны сравнения являются столбцами или составными выражениями, настройка не влияет на сравнение.
Так что я думаю, NOT
операция проверяет 1=NULL
который неизвестен и потому что это не переменная или буквальный NULL, получает ELSE часть вашего сравнения, как вы предположили.
Попробуйте использовать EXISTS в подзапросе, он использует 2-значную логику и даст вам истинное / ложное значение, которое вы ищете.