这是我遇到的问题:我有一个大型查询需要比较where子句中的日期时间,以查看两个日期是否在同一天.我当前的解决方案很糟糕,是将日期时间发送到UDF以将它们转换为同一天的午夜,然后检查这些日期是否相等.当涉及到查询计划时,这是一场灾难,几乎所有联接中的UDF或where子句都是如此.这是我的应用程序中唯一一个我无法根除函数并为查询优化器提供实际可用于查找最佳索引的地方之一.
在这种情况下,将函数代码合并回查询似乎是不切实际的.
我想我在这里缺少一些简单的东西.
这是参考功能.
if not exists (select * from dbo.sysobjects where id = object_id(N'dbo.f_MakeDate') and type in (N'FN', N'IF', N'TF', N'FS', N'FT')) exec('create function dbo.f_MakeDate() returns int as begin declare @retval int return @retval end') go alter function dbo.f_MakeDate ( @Day datetime, @Hour int, @Minute int ) returns datetime as /* Creates a datetime using the year-month-day portion of @Day, and the @Hour and @Minute provided */ begin declare @retval datetime set @retval = cast( cast(datepart(m, @Day) as varchar(2)) + '/' + cast(datepart(d, @Day) as varchar(2)) + '/' + cast(datepart(yyyy, @Day) as varchar(4)) + ' ' + cast(@Hour as varchar(2)) + ':' + cast(@Minute as varchar(2)) as datetime) return @retval end go
更复杂的是,我正在加入时区表来检查当地时间的日期,每行可能会有所不同:
where dbo.f_MakeDate(dateadd(hh, tz.Offset + case when ds.LocalTimeZone is not null then 1 else 0 end, t.TheDateINeedToCheck), 0, 0) = @activityDateMidnight
[编辑]
我正在纳入@Todd的建议:
where datediff(day, dateadd(hh, tz.Offset + case when ds.LocalTimeZone is not null then 1 else 0 end, t.TheDateINeedToCheck), @ActivityDate) = 0
我对约瑟夫如何工作的误解(连续几年的同一天产生366,而不是我预期的0)导致我浪费了很多精力.
但查询计划没有改变.我想我需要回到整个事情的绘图板.
这更简洁:
where datediff(day, date1, date2) = 0
你几乎必须保持where子句的左侧清洁.所以,通常情况下,你会这样做:
WHERE MyDateTime >= @activityDateMidnight AND MyDateTime < (@activityDateMidnight + 1)
(有些人更喜欢DATEADD(d,1,@ activityDateMidnight) - 但这是相同的事情).
TimeZone表虽然有点复杂.你的片段有点不清楚,但它看起来像是.DateInTable在GMT中带有时区标识符,然后你要添加偏移量来与@activityDateMidnight进行比较 - 这是当地时间.不过,我不确定ds.LocalTimeZone是什么.
如果是这种情况,那么你需要将@activityDateMidnight改为GMT.
where year(date1) = year(date2) and month(date1) = month(date2) and day(date1) = day(date2)