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-значную логику и даст вам истинное / ложное значение, которое вы ищете.

Другие вопросы по тегам