在跨越闰年的时段中跨多年分组选择语句

时间:2013-01-23 13:43:01

标签: sql sql-server tsql leap-year

我有这个查询,它选择跨越iMAXYears的所有记录,直到2012年11月30日:

 SELECT sum([AllocatedAmount]) as total, 
 datediff(day,transactiondate,'30 Nov 2012') / DaysInyear AS YearDiff 
 FROM tblGroups 
 AND datediff(day,transactiondate, '30 Nov 2012') / DaysInyear < iMaxYears
 AND not transactiondate > '30 Nov 2012'  
 GROUP BY g.groupdescription, nominal, 
 datediff(day,transactiondate, '30 Nov 2012') / DaysInyear

出于本问题的目的,2012年11月30日是硬编码的(变量名= lMaxDate),iMaxYears是3

我的问题是,DaysInYear的值通常为365,但在闰年中的值为366.

在2012年的闰年,由于2012年2月29日,上述声明并未在2011年12月1日回升。

我知道

DaysInYear=(CASE WHEN (year % 4 = 0 AND year % 100 <> 0) 
OR year % 400 = 0 then 366 else 365)

Currently DaysInYear = 365.

我应该创建一个功能

DaysInYear(lYear) where you pass in a year (lYear) 
and it returns 365 or 366?

问题是我无法通过Year(transactiondate),因为年份将始终跨越2年的部分时间,iMaxYears意味着我们可以在结果集中有4个年度周期。

有什么想法吗?感谢

2 个答案:

答案 0 :(得分:0)

如果您只使用该case语句代替DaysInYear变量怎么办?

    SELECT sum([AllocatedAmount]) as total, 
 datediff(day,transactiondate,'30 Nov 2012') / CASE WHEN (year % 4 = 0 AND year % 100 <> 0) 
OR year % 400 = 0 then 366 else 365 end AS YearDiff 
 FROM tblGroups 
 AND datediff(day,transactiondate, '30 Nov 2012') / CASE WHEN (year % 4 = 0 AND year % 100 <> 0) 
OR year % 400 = 0 then 366 else 365 end < iMaxYears
 AND not transactiondate > '30 Nov 2012'  
 GROUP BY g.groupdescription, nominal, 
 datediff(day,transactiondate, '30 Nov 2012') / CASE WHEN (year % 4 = 0 AND year % 100 <> 0) 
OR year % 400 = 0 then 366 else 365 end

只要年份中的天数值基于相关交易日期,您就应该明确。

答案 1 :(得分:0)

如果您从transactionDate中删除29天和10个月,则可以将截止点移至1月1日。这样,DATEADD会为您减去适当的天数。

CREATE FUNCTION yearDiff(@maxDate DATE, @transactionDate DATE)
RETURNS INT AS
BEGIN
  DECLARE @dayDiff INT
  DECLARE @monthDiff INT

  -- Determine how many months and days @maxDate is from the first of january
  SET @monthDiff = 1 - DATEPART(MONTH, @maxDate)
  SET @dayDiff = 1 - DATEPART(DAY, @maxDate)

  -- Determine how many years away from @maxDate the transaction is
  RETURN DATEDIFF(YEAR,
                  DATEADD(MONTH,
                          @monthDiff,
                          DATEADD(DAY,
                                  @dayDiff,
                                  @transactionDate)
                          ),
                  @maxDate
                  )
END

我认为你的选择会是这样的:

SELECT
  sum(amount) [total],
  dbo.yearDiff(@maxDate, transactionDate) [yearDiff]
FROM tblGroups
WHERE  transactionDate <= @maxDate
AND dbo.yearDiff(@maxDate, transactionDate) <= @iMaxYears
GROUP BY dbo.yearDiff(@maxDate, transactionDate)

http://sqlfiddle.com/#!6/54c2d/2

优点是它既美观又可读,而且你没有神奇的数字。它不是特别有效,如果有很多事务,你会想要内联函数调用或者为yearDiff添加一个计算列。