认为
isnull(some_column, getdate()) >= getdate()
其中逻辑是如果 some_column 为空,则此表达式应始终为真。然而,这是否总是如此(因为在 getdate() 的两次评估之间已经过去了一段时间并且它们不会相等)?
认为
isnull(some_column, getdate()) >= getdate()
其中逻辑是如果 some_column 为空,则此表达式应始终为真。然而,这是否总是如此(因为在 getdate() 的两次评估之间已经过去了一段时间并且它们不会相等)?
不,不安全。您面临所谓的运行时常量表达式,其中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()
语句中的两次将被评估两次
由于您在条件中寻找 true,因此您不需要使用getDate()
两次。只需输入一个非常大的日期...
例如:
isnull(some_column, '2999-01-01') >= getDate()
如在
declare @some_column(datetime)
select case when isnull(@some_column,'2999-01-01') >= getdate() then 1 else 0 end
返回 1。
或者,您可以正确执行并明确检查 null:
(some_column >= getdate() or some_column is null)
在 SQL Server 2000 和以前的版本中,getdate() 是一个确定性函数,每个 SQL 语句计算一次。从 2005 年起,getdate 不是确定性的,每次都会对其进行评估,因此您应该将值分配给变量。
由于您调用了GETDATE()
两次,这可能会失败,但大多数情况下它会正常工作。
您可以执行以下操作来缓解:
DECLARE currentDate DATETIME
SELECT currentDate = GETDATE()
isnull(some_column, currentDate) >= currentDate
为什么要使用日期。我的意思是没有理由要求 sql server 评估/处理默认的真实条件。您可以改为使用
isnull(some_column, 2) >= 1