T-SQL: что НЕТ (1 = NULL)? - PullRequest
       9

T-SQL: что НЕТ (1 = NULL)?

7 голосов
/ 14 марта 2012

У меня нет простой логической алгебры на моем 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)

Print-Statement пишет «False», но вставка выполняется без ошибок.SQL-Server, по-видимому, отрицает проверочное ограничение, чтобы искать строки, которые не выполняют проверку ограничения:

IF EXISTS (SELECT * FROM inserted WHERE NOT(Value>NULL)) <Generate error>

Поскольку проверочное ограничение оценивается как UNKNOWN, отрицание также UNKNOWN и SqlServerне находит ни одной строки, нарушающей ограничение проверки.

Ответы [ 7 ]

6 голосов
/ 14 марта 2012

Да, эта ссылка неправильная. Отправить документацию об ошибке на Microsoft Connect .

Sql использует трехзначную логику, а не булеву логику. true, false и unknown

Большинство операторов сравнения (т.е. исключая IS [NOT] NULL), включающих NULL, приводят к unknown, а не True или False. Отрицание неизвестного дает неизвестное в соответствии с таблицами истинности , показанными здесь .

5 голосов
/ 14 марта 2012

Страница MSDN для «Равных», на которую вы ссылаетесь, определенно отображается неверно.

Проверьте страницу MSDN для SET ANSI_NULLS .

Когда SET ANSI_NULLS включен, все сравнения с нулевым значением оценить до НЕИЗВЕСТНО.

Чтобы этот пример оператора SQL работал должным образом, вы должны использовать сравнение, используя "IS NULL" или "IS NOT NULL" вместо использования оператора равенства (=). Например:

SELECT CASE WHEN NOT(1 IS NULL) THEN 1 ELSE 0 END

OR

SELECT CASE WHEN (1 IS NOT NULL) THEN 1 ELSE 0 END

2 голосов
/ 14 марта 2012

Это не булева логика, а ее триальная логика: {Правда, Ложь, я не знаю.} Разбейте это следующим образом:

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.

Короче, насколько я понимаю, документация неверна.Удручает, но не уникально, и поэтому не совсем удивительно.

2 голосов
/ 14 марта 2012

Вы хотите прочитать документацию на 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 2012 , параметр ANSI_NULLS был удален, и поэтому его установка любым способом не изменит результат.

0 голосов
/ 14 марта 2012

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
0 голосов
/ 14 марта 2012

От BOL (кредит до Томас ):

SET ANSI_NULLS ON влияет на сравнение, только если один из операндов сравнения является либо переменной, равной NULL, либобуквальный NULL.Если обе стороны сравнения являются столбцами или составными выражениями, настройка не влияет на сравнение.

Поэтому я предполагаю, что операция NOT проверяет 1=NULL, что неизвестно, и потому что это непеременная или литерал NULL получает ELSE часть вашего сравнения, как вы и предполагали.

0 голосов
/ 14 марта 2012

Попробуйте использовать EXISTS в подзапросе, он использует 2-значную логику и даст вам искомое значение / ложь.

...