回答

收藏

在TSQL中检查两个日期时间是否在同一日历日的一种好方法是什么?

技术问答 技术问答 306 人阅读 | 0 人回复 | 2023-09-14

这是我遇到的问题:我有一个大型查询,需要比较where子句中的日期时间以查看两个日期是否在同一天。我当前的解决方法很糟糕,就是将日期时间发送到UDF中,以将其转换为同一天的午夜,然后检查这些日期是否相等。当涉及到查询计划时,这是一场灾难,联接或where子句中的几乎所有UDF都是如此。这是我的应用程序中唯一无法根除函数并为查询优化器提供一些可以实际用于定位最佳索引的地方之一。
( E" F- R$ S  C8 s/ y8 g在这种情况下,将功能代码合并回查询中似乎是不切实际的。
# q% C& R6 a4 N1 a我想我在这里错过了一些简单的事情。# m# f2 B! X& O, {
这是供参考的功能。6 k! J2 _8 I' C5 I0 Z% i" }6 Z0 h
if not exists (select * from dbo.sysobjects & ]2 L7 N1 U' W* V% _& v2 }0 R# ]
              where id = object_id(N'dbo.f_MakeDate') and               - h+ S% \+ P& _  E0 r9 C9 |1 A% P
              type in (N'FN', N'IF', N'TF', N'FS', N'FT'))! w& E* I1 @% J
  exec('create function dbo.f_MakeDate() returns int as
& H9 g1 y/ |# Z" z% X! b& @         begin declare @retval int return @retval end')
7 R5 V: R* [  |go
( `  H9 c: p7 }; Halter function dbo.f_MakeDate; u  K& _3 v  H
(: k  G0 X, E/ u; ^5 u0 J3 S
    @Day datetime,
. R& J2 J6 G; `8 \  B' V! R' t    @Hour int, & V5 B: {5 ?6 w" t. `8 K
    @Minute int
' K8 A2 _" x2 ~- `# ^# i& l+ @)
. r9 s: `% i: \2 Y; a  yreturns datetime" o, Z0 @1 s9 O# m+ H. i/ }
as, l/ ?5 Q8 j' W, `
/*
# S% g6 D$ A" F& z+ ]  I  v. k# sCreates a datetime using the year-month-day portion of @Day, and the * L- {& d% K; \4 f0 F( U0 g
@Hour and @Minute provided
9 Y5 J, u+ b) v9 n7 k*/  j; H- E# g6 a6 d
begin, t1 ~1 N5 V" `& f, y
declare @retval datetime4 u8 y4 o! ]( a) {/ E
set @retval = cast(. U+ _& q) p7 L
    cast(datepart(m, @Day) as varchar(2)) + ' N0 g& F7 S  r$ m8 F, y7 _
    '/' +
- F$ O2 E" d- Y+ M    cast(datepart(d, @Day) as varchar(2)) +
4 _# ?& H8 [6 _% Q" n' `# y    '/' +
! q7 L0 n6 d* M& \. C' U0 G    cast(datepart(yyyy, @Day) as varchar(4)) +
3 x! k" g2 R9 _4 W: u    ' ' +
2 J4 A" k7 w* J- S' K/ ^! n2 c' p    cast(@Hour as varchar(2)) + ; T5 h; B9 S1 N/ u6 z) K' {
    ':' + " j. M7 c0 S. d4 I1 P% K! g
    cast(@Minute as varchar(2)) as datetime)
. l8 a% m1 {8 t- Treturn @retval8 A+ |- x% ~5 J, r( \5 r  K
end. h# h) U5 b8 g  n/ M: @7 q) x8 M
go/ y) I) u; L) k7 D
使事情复杂化的是,我加入了时区表,以对照当地时间检查日期,每行的日期可能不同:
  z  Z% g! v4 M; Dwhere 6 x7 s: k# ]* w5 U
dbo.f_MakeDate(dateadd(hh, tz.Offset +
( Q8 f1 T; n: Z6 w    case when ds.LocalTimeZone is not null ) A) g* T5 x* I' M
    then 1 else 0 end, t.TheDateINeedToCheck), 0, 0) = @activityDateMidnight  S7 B4 @4 F# B* P7 C7 r$ I4 O
[编辑]1 R9 F# s' u. \3 a, R+ t+ X# }! t
我纳入@Todd的建议:
% F9 k- K9 b- ], j# Swhere datediff(day, dateadd(hh, tz.Offset + " G* E" u) u7 v6 j* |
    case when ds.LocalTimeZone is not null 8 b3 J3 n1 k" i' I7 u
    then 1 else 0 end, t.TheDateINeedToCheck), @ActivityDate) = 0+ r( P* B' g# p3 h
我对datediff的工作方式存在误解(连续几年的同一天,结果为366,而不是我预期的0),这使我浪费了很多精力。
, }" c* s  p* R1 X0 o# f' u/ R但是查询计划没有改变。我想我需要把整个事情都回到图纸上。3 n# N& F( A1 [1 y: x& X
               
( q  U, H  Z' Y6 z' L* A& N  a  d解决方案:
# C. V& z, N% s% j$ P               
: T) i9 ?; s* s( Y! y
6 z' w( T( k# d% }% ^
& z0 N  m& U. W8 S) f; a! s' X                这更加简洁:
, R- g& n4 v0 }0 |! O; v+ F6 R/ F, gwhere / i2 n  c2 ~3 E" }4 q9 o
  datediff(day, date1, date2) = 0
分享到:
您需要登录后才可以回帖 登录 | 立即注册

本版积分规则