Работа с пустыми значениями в сравнительных тестах в SQL Server 2005 - PullRequest
1 голос
/ 16 апреля 2009

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

SET ANSI_NULLS ON;
DECLARE @1 INT;
DECLARE @2 INT;
DECLARE @3 INT;
DECLARE @4 INT;

SET @1 = 1;
SET @2 = NULL;
SET @3 = 3;
SET @4 = 3;

IF ((@1 <> @2) OR (@3 <> @4))
   BEGIN
     SELECT 1;
   END
ELSE
   BEGIN
     SELECT 2;
   END
SELECT @1, @2, @3, @4

Возвращает:

2

1, NULL, 3, 3

Я ожидал, что он вернется:

1

1, NULL, 3, 3

Я знаю, что упускаю что-то простое, у кого-нибудь есть идеи, что это такое?

Смежный вопрос

SQL: Почему NULL Значения отфильтрованы в этом предложении WHERE?

Ответы [ 5 ]

5 голосов
/ 16 апреля 2009

Один из способов справиться с этим - вы можете обернуть ваши значения NULL в известное неожиданное значение, т.е. -1:

IF ((ISNULL(@1, -1) <> ISNULL(@2, -1)) OR (ISNULL(@3, -1) <> ISNULL(@4, -1)))
   BEGIN
     SELECT 1;
   END
ELSE
   BEGIN
     SELECT 2;
   END

Очевидно, что если -1 была возможность, используйте другое число. Если нет невозможного значения, вам придется использовать CASE операторов.

Ниже приведен краткий способ присвоения NULL значений «безопасным» значениям:

SET @1 = ISNULL(@1, -1)

Это позволяет условному тестовому коду оставаться свободным от помех.

4 голосов
/ 16 апреля 2009

Любое сравнение, которое включает в себя NULL, будет оцениваться как NULL вместо True или False. Следовательно, выполняется ELSE-блок вашего кода. Потому что, хотя Null не совпадает с False, оно определенно не совпадает с True.

2 голосов
/ 16 апреля 2009

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

IF (@1 IS NULL AND @2 IS NULL) OR (@1 = @2)
BEGIN
    IF (@3 IS NULL AND @4 IS NULL) OR (@3 = @4) 
    BEGIN
        SELECT 2
    END
    ELSE
    BEGIN
        SELECT 1
    END
END
ELSE
BEGIN
    SELECT 1
END
2 голосов
/ 16 апреля 2009

Да, нули - это боль. Несколько способов справиться с ними. Некоторые из них являются специфическими функциями MS-SQL:

Метод 1: Будьте откровенны во всех опциях

IF ((@1 <> @2) 
OR (@1 is NULL AND @1 IS NOT NULL)
OR (@1 is NOT NULL AND @1 IS NULL)
OR (@3 <> @4)
OR (@3 is NULL AND @4 IS NOT NULL)
OR (@3 is NOT NULL AND @4 IS NULL))

Метод 2: Мы используем функцию для преобразования нуля во что-то другое, что, как вы знаете, не будет совпадать:

IF ((IsNull(@1,-1) <> IsNull(@2,-1) 
OR (IsNull(@3,-1) <> IsNull(@4,-1))

Иногда этот первый вариант лучше, потому что он более явный. Второй имеет побочный эффект от сопоставления NULL с NULL.

Редактировать: если вы хотите установить их заранее, просто наберите

SET @1 = IsNull(@1,-1);

Если он равен нулю, он будет установлен в -1. Если нет, он оставит это в покое. Я думаю, что чище сделать это внутри функции, в соответствии с моим методом 2.

1 голос
/ 16 апреля 2009

Если вы хотите еще больше запутаться, попробуйте запустить противоположный тест следующим образом:

SET ANSI_NULLS ON;
DECLARE @1 INT;
DECLARE @2 INT;
DECLARE @3 INT;
DECLARE @4 INT;
SET @1 = 1;
SET @2 = NULL;
SET @3 = 3;
SET @4 = 3;
IF ((@1 = @2) AND (@3 = @4))
   BEGIN     SELECT 1;
   ENDELSE   
   BEGIN     SELECT 2;   
   END
SELECT @1, @2, @3, @4

Результат будет не таким, как вы ожидаете от предыдущего эксперимента.

Причина в том, что SQL использует сложную логику из трех значений при оценке выражения, которые могут содержать значения NULL.

NULL = 3 не ИСТИНА. Это тоже не ЛОЖЬ. Это NULL. NULL = NULL не ИСТИНА. Это тоже не ЛОЖЬ. Это NULL.

С этим легко все перепутать. Лучший способ избежать путаницы состоит в том, чтобы все ваши критические данные были не пустыми. Тем не менее, требования могут помешать вам сделать это, и в этом случае вам просто нужно будет определить 3-х значную логику, стиль SQL.

Не проси меня защищать это.

(В некоторых средах UNKNOWN используется вместо NULL для результатов, которые не равны ИСТИНА или ЛОЖЬ.)

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...