Двойная оценка GETDATE в операторе — всегда ли она будет оцениваться одинаково?

предполагать

isnull(some_column, getdate()) >= getdate()

где логика, если some_column имеет значение null, это выражение всегда должно быть истинным. Однако будет ли это всегда так (поскольку между двумя оценками getdate() прошло некоторое время, и они не будут равны)?


person ren    schedule 20.08.2012    source источник


Ответы (5)


Нет, не безопасно. Вы столкнулись с так называемым константы времени выполнения, из которых GETDATE() является примером книжного шкафа, которые оцениваются один раз при запуске запроса, а затем используется кэшированное оцененное значение. Однако каждое вхождение оценивается отдельно один раз, и две оценки могут приходиться на разные стороны границы точности даты и времени, что приводит к двум разным значениям.

Простой тест показывает, как это происходит:

declare @cnt int = 0, @i int = 0
while @cnt = 0 
begin
    select @cnt = count(*)
    from master..spt_values 
    where getdate() != getdate();
    set @i += 1;
    if @cnt != 0
        raiserror(N'@cnt = %d this shoudl not happen but it dit after @i = %d', 16, 1, @cnt, @i);
end

В моем случае это было сразу же поражено:

Msg 50000, Level 16, State 1, Line 9
@cnt = 2515 this shoudl not happen but it dit after @i = 694

Я не рассматриваю вопрос о том, как лучше это сделать (у вас уже есть много советов), но основной вопрос, верно ли ваше предположение о выполнении во время выполнения (нет):

GETDATE() дважды в операторе будет оцениваться дважды

person Remus Rusanu    schedule 20.08.2012

Поскольку вы ищете true в условии, вам не нужно использовать getDate() дважды. Просто вставьте очень большую дату вместо этого...

Например:

isnull(some_column, '2999-01-01') >= getDate()

as in

declare @some_column(datetime)
select case when isnull(@some_column,'2999-01-01') >= getdate() then 1 else 0 end

который возвращает 1.

В качестве альтернативы вы можете сделать это правильно и явно проверить нуль:

(some_column >= getdate() or some_column is null)
person Jon Egerton    schedule 20.08.2012

В SQL Server 2000 и предыдущих версиях getdate() — это детерминированная функция, вычисляемая ОДИН РАЗ для каждого предложения SQL. С 2005 года и далее getdate НЕ является детерминированным, он оценивается каждый раз, поэтому вы должны присвоить значение переменной.

person Yván Ecarri    schedule 20.08.2012

Поскольку вы вызываете GETDATE() дважды, это может завершиться ошибкой, хотя в большинстве случаев все будет работать правильно.

Вы можете сделать следующее, чтобы смягчить:

DECLARE currentDate DATETIME

SELECT currentDate = GETDATE()

isnull(some_column, currentDate) >= currentDate 
person Oded    schedule 20.08.2012

Почему вы хотите использовать дату. Я имею в виду, что нет причин просить сервер sql оценивать/обрабатывать истинное состояние по умолчанию. Вместо этого вы можете использовать

isnull(some_column, 2) >= 1
person NG.    schedule 20.08.2012