繁体   English   中英

SQL Server 2005查询DateDate

[英]SQL Server 2005 Query DateDate

WHERE
   StartDate BETWEEN 
       CAST(FLOOR(CAST(DATEADD("month", - 12, ISNULL(RunDate.testdate, GETDATE()) - DAY(ISNULL(RunDate.testdate, GETDATE())) + 1) AS FLOAT)) AS DATETIME)
       AND 
       CAST(FLOOR(CAST(ISNULL(RunDate.testdate, GETDATE()) - DAY(ISNULL(RunDate.testdate, GETDATE())) + 1 AS FLOAT)) AS DATETIME)

/************************************************* 
SQL Server 2005 (9.0 SP4)
StartDate is of TYPE DATETIME
StartDate date looks like 2012-07-05 12:45:10.227
RunDate is a TABLE with no records
RunDate.testdate is always NULL
**************************************************/

WHERE子句可以正常工作并产生业务期望的预期结果,但看起来过于混乱。

试图实现的所有目的就是将任何一年的7月运行的过去12个月的所有记录汇总在一起。 因此记录了2013年7月1日至2014年6月30日。

这是另一个表达式:

where startdate > cast(dateadd(year, -1, getdate() - day(getdate()) as date) and
      startdate <= cast(getdate() - day(getdate()) as date)

当您从datetime减去数字时,将其视为天数,这更易于阅读。

编辑:

哦,那是2005年,而不是2008年。日期逻辑是这样的。

where startdate > cast(dateadd(year, -1, dateadd(day, - day(getdate()), getdate()) as date) and
      startdate <= cast(dateadd(day, - day(getdate()), getdate())

但是您会在约会上有时间。 实际上,没有简单的方法可以将其转换为日期。 您可以使用子查询更轻松地执行此操作:

from (select dateadd(day, 0, datediff(day, 0, getdate())) as today) const
where startdate > dateadd(year, -1, dateadd(day, - day(today), today) and
      startdate <= cast(dateadd(day, - day(today), today)

我的第一个问题是:您希望看到有人在七月以外的任何时间执行此操作吗?

切勿承担超出您控制范围的事情。 您无法控制何时执行此操作,因此请对其进行编写,以使其始终在正确的时间段内执行,无论如何。

因为有许多方法可以基于DBMS甚至是DBMS版本(例如,SS 2005 vs 2008)来完成此任务,所以这里是有人说的:

 -- Get the difference, in years, between sysdate and the base date
 -- Add that to the base date. You now have Jan 1 of whatever year it is.
 -- Add 6 months. You now have Jul 1 of that year.
 -- Add 1 year and subtract 1 day. You now have Jun 30 of the following year.

现在,无论何时执行查询,查询都将在正确的范围内运行。 当然,如果在2月执行,则结果将不完整,因为某些范围会在将来出现。 但是结果在执行时始终是正确的。

您可以进行的一种调整是,如果在任何一年的7月1日之前执行该调整,则会生成最近一个完整年份的范围。 因此,如果2014年7月1日之前的任何时间执行,则为2012年7月1日至2013年6月30日。

[编辑:我想自从提出以来,我应该指定如何做到这一点。 在上面的第一步中,将其显示为sysdate ,将其更改为(sysdate minus 6 months)

只要您的用户知道期望什么,实际上用哪种方式设计都没关系。 但是无论您做什么,都不要让查询取决于用户在正确的时间执行查询的能力。

如果您放弃了x BETWEEN a AND b模式之间 ,而将其大致表示为

x BEGINS WITH a
  ENDS BEFORE b

(当然,这不是有效的SQL语法,但x >= a AND x < b将是一个不错的替代),您将最终得到ab具有相同的粒度(具体来说是几个月),因为两点各将是一个月的开始)。

在这种情况下,这是非常合适的,因为它将允许您很好地分解ab计算。 但是在到达那里之前,让我告诉(或提醒)您有关SQL Server中这种日期/时间截断技术的信息

DATEADD(, DATEDIFF(, , ), )

在您的情况下, unitMONTH 对于SomeFixedDate ,有一种简便的做法是使用0表示简洁,0表示1900-01-01 1的日期。

因此,使用此技术,本月初将计算为

DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0)

那将是您间隔的尽头。 间隔的开始将是相同的,除了您将从DATEDIFF的结果中减去12,因此匹配范围的完整条件如下所示:

WHERE StartDate >= DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()) - 12, 0)
  AND StartDate <  DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0)

如果您仍然觉得这很麻烦,则可以尝试摆脱DATEDIFF(MONTH, 0, GETDATE())的重复。 您可以将其视为某个抽象的月份号,并在两个DATEADD调用中均将其引用。 CROSS APPLY语法将帮助您:

…
CROSS APPLY (
  SELECT DATEDIFF(MONTH, 0, GETDATE())
) AS x (MonthNo)
WHERE StartDate >= DATEADD(MONTH, x.MonthNo-12, 0)
  AND StartDate <  DATEADD(MONTH, x.MonthNo   , 0)

是的,这似乎可以分解。 但是,它可能无法很好地提高可读性。 有人(甚至是您自己,在以后的某个时间)可能会看着它说:“ MonthNoMonthNo ?那到底是什么?啊, 那个数字……”如果我要考虑间隔计算,我可能会考虑以下几点:

…
CROSS APPLY (
  SELECT DATEADD(MONTH, DATEDIFF(MONTH, 0, GETDATE()), 0)
) AS x (ThisMonth)
WHERE StartDate >= DATEADD(YEAR, -1, x.ThisMonth)
  AND StartDate <  x.ThisMonth

不过,我承认,可读性并不是一个完美的客观标准,有时人们会根据自己的个人喜好/偏好选择一种书写方式。


1尽管将日期硬编码为整数值不是正常做法,但我认为这种截断技术是一种特殊情况,其中使用0代替日期时间值应该可以:这种用法似乎非常普遍,以至于可能到现在已经成为使用它的人中的“固定表达”,因此,不太可能引起混乱。

在SQL Server 2005中,可以使用DATEADDDATEDIFF删除时间部分并计算确切的月边界:

WHERE 
    startdate >= DATEADD(year, -1, DATEADD(month, DATEDIFF(month, '', GETDATE()), ''))
    AND startdate > DATEADD(month, DATEDIFF(month, '', GETDATE()), '')

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM