为什么这两个SQL日期函数不能提供相同的答案

时间:2019-05-31 07:21:06

标签: tsql

我实际上已经解决了问题,但是我试图理解为什么会发生此问题,因为据我所知,没有理由发生此问题。 我有一个相当大的查询,可以运行以准备一些常用组合的表。通常,它仅包含2年的数据。有时我会重建它。在执行此操作时,我对查询进行了调整以添加更多信息,但是突然结果不再与旧查询匹配。将新旧版本进行比较,我注意到一些缺失的订单。令人惊讶的是,即使删除了经过调整的部分,结果仍然不匹配。

我最终将问题追溯到我的WHERE子句,这与我上次的处理方式不同。

我要查看的orderdate列的类型为(datetime,null)

其中一个被省略的订单的日期为:

2018-12-23 20:58:52.383

其中包含的订单的日期为:

2019-01-28 15:20:49.107

对我来说看起来完全一样。

除了WHERE子句外,整个查询是相同的。我原来的位置是:

WHERE DATEPART(yyyy,tbOrder.[OrderDate]) >= DATEPART(yyyy,GETDATE()-2)

我现在的新位置:

WHERE tborder.[OrderDate] >= DATEADD(yy, DATEDIFF(yy, 0, GETDATE())-2, 0)

对于理解为什么原始的where子句删除某些行的任何帮助,将不胜感激。

2 个答案:

答案 0 :(得分:0)

因为您正在做两种不同的事情。第一个谓词

WHERE DATEPART(yyyy,tbOrder.[OrderDate]) >= DATEPART(yyyy,GETDATE()-2)

取所有大于前一天或前两天的年份的订单日期。请注意,-2在方括号内。

第二个谓词

WHERE tborder.[OrderDate] >= DATEADD( yy, DATEDIFF( yy, 0, GETDATE() ) - 2, 0)

取所有大于两年前的订单日期,即datediff(yy,startdate,enddate)将返回今天与date数据类型的初始值(1900-01-01)之间的差值的年份结果。然后,将-2添加到1900-01-01。第二个表达式的形式为:

  

1900 +(201X-1898)

我简化了1900-2 = 1898。

答案 1 :(得分:0)

这两个表达式返回的结果完全不同,因此结果不同也就不足为奇了。第一个以数字形式返回 current 年(准确地说是前一天的年份)。第二个返回两年前的1月1日。

您可以将两个表达式都放在SELECT查询中,以查看它们返回的内容:

select DATEPART(yyyy,GETDATE()-2),  DATEADD(yy, DATEDIFF(yy, 0, GETDATE()) - 2, 0)

结果是:

2019    2017-01-01 00:00:00.000

两个表达式都比它们需要的复杂。 first 条件也会损害性能,因为DATEPART(yyyy,tbOrder.[OrderDate])阻止服务器使用覆盖OrderDate的任何索引。

该问题并未说明您实际要返回的内容。如果您想返回当年的所有行,可以使用:

Where 
    OrderDate >=DATEFROMPARTS( YEAR(GETDATE()) ,1,1) and 
    OrderDate < DATEFROMPARTS( YEAR(GETDATE()) + 1,1,1)

同样可以用来查找过去两年的行:

Where 
    OrderDate >= DATEFROMPARTS( YEAR(GETDATE()) -2 ,1,1) and 
    OrderDate < DATEFROMPARTS(YEAR(GETDATE()) - 1,1,1)

两年前1月1日以来的所有行:

Where OrderDate >= DATEFROMPARTS( YEAR(GETDATE()) -2 ,1,1) 

所有这些查询都可以利用覆盖OrderDate的索引。

如果您使用Calendar table,则

日期范围查询将变得更容易很多。日历表是一个表,其中包含例如50或100年的日期,并带有月份,月份,星期几,星期几,季度,学期,月份和日期名称,假期,业务重复期,格式短的额外列,长约会等

这使年度,每月或每周查询与加入“日历”表并根据所需的月份或期间进行过滤一样容易。

在这种情况下,过去两次检索行看起来像:

From Orders inner Join Calendar on OrderDate=Calendar.Date
Where Calendar.Year=YEAR(GETDATE())-2

这看起来可能并不令人印象深刻,但是两年前的第二季度呢?

From Orders inner Join Calendar on OrderDate=Calendar.Date
Where Calendar.Year=YEAR(GETDATE())-2 and Quarter=2

两年前,同一季度

From Orders inner Join Calendar on OrderDate=Calendar.Date
Where Calendar.Year=YEAR(GETDATE())-2 and Quarter=DATEPART(q,GETDATE())

检索过去两年中当前季度的总计:

SELECT Year,Quarter,SUM(Total) QuarterTotal
From Orders inner Join Calendar on OrderDate=Calendar.Date
Where Calendar.Year > YEAR(GETDATE())-2 and Quarter=DATEPART(q,GETDATE())
GROUP BY Calendar.Year