Используйте условие WHERE в SQL, где параметры могут быть NULL - PullRequest
0 голосов
/ 09 февраля 2020

Всем доброго времени суток.

Я написал хранимую процедуру, которая принимает на вход некоторые параметры (INT, VARCHAR, Date). Все они имеют значение NULL.

У меня проблема при настройке условие:

@day DATE NULL
@age INT NULL
@nome VARCHAR(50) NULL

SELECT *
    FROM [table]
    WHERE   (ISNULL(@day, CURRENT_TIMESTAMP) = CURRENT_TIMESTAMP OR [table].[day] = @day)
        AND (ISNULL(@age, 0) = 0 OR [table].age = @age)
        AND (LEN(ISNULL(LTRIM(RTRIM(@name)),'')) = 0 OR [table].name LIKE '%' + LTRIM(RTRIM(@name)) + '%') 

Условия для age и name работают очень хорошо.

day доставляет мне некоторые неприятности. Если я использую NULL вместо параметра в условии (ISNULL(NULL, CURRENT_TIMESTAMP) = CURRENT_TIMESTAMP OR [table].[day] = @day), это работает, и я получаю все содержимое таблицы относительно других условий, в противном случае, если @day установлено как NULL, запрос не ничего не вернуть.

Ответы [ 2 ]

1 голос
/ 09 февраля 2020

Вероятно, в этом выражении:

ISNULL(@day, CURRENT_TIMESTAMP) = CURRENT_TIMESTAMP

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

declare @day date = null;
select 1
where isnull(@day, current_timestamp) = current_timestamp

, который ничего не возвращает. Но если вместо переменной вы используете null:

select 1
where isnull(null, current_timestamp) = current_timestamp

, то обе стороны оцениваются один раз и для всего оператора, и результат равен true, так что вы получите результаты.

Но если вы сохраните возвращаемое значение current_timestamp в переменной, например:

declare @currentday date = current_timestamp;
declare @day date = null;
select 1
where isnull(@day, @currentday) = @currentday

, то вы можете быть уверены, что сравниваете ту же метку времени, и вы получите результаты , См. демо .

0 голосов
/ 09 февраля 2020

Я подозреваю, что ваш ответ из-за недетерминированной c природы функции CURRENT_TIMESTAMP. Значения рассчитываются по-разному для каждой реализации, и поэтому они не устанавливаются в одно и то же значение в вашем сравнении.

Вам необходимо сравнить с чем-то детерминированным c - возможно, используя тот факт, что базовая дата значение всегда одинаково

WHERE   ISNULL(@d, DATEADD(DAY, 0, 0)) = DATEADD(DAY, 0, 0)
...