假设
isnull(some_column, getdate()) >= getdate()
其中逻辑是,如果some_column为null,则此表达式应始终为true。然而,这总是如此(因为在两次getdate()评估之间已经过了一段时间并且它们不会相等)?
答案 0 :(得分:5)
不,不安全。您正面临所谓的runtime constants表达式,其中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()
两次将进行两次评估
答案 1 :(得分:3)
由于您在条件中寻找真实,因此您无需使用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)
答案 2 :(得分:2)
由于 两次调用GETDATE()
,此可能失败,但大部分时间它都可以正常工作。
您可以执行以下操作来缓解:
DECLARE currentDate DATETIME
SELECT currentDate = GETDATE()
isnull(some_column, currentDate) >= currentDate
答案 3 :(得分:1)
在SQL Server 2000和以前的版本中,getdate()是一个按每个SQL语句评估ONCE的确定性函数。从2005年开始,getdate不是确定性的,每次都会对它进行评估,因此您应该将值赋给变量。
答案 4 :(得分:0)
为什么要使用日期?我的意思是没有理由要求sql server评估/处理默认的真实条件。 您可以改为使用
isnull(some_column, 2) >= 1