DATEDIFF不包括夏季

时间:2015-06-30 19:18:30

标签: sql sql-server

我们正在为季节性业务运行报告,预计夏季将会出现平静期。对于某些指标,我们基本上想假装那些月份甚至不存在。

因此,请考虑以下的默认行为:

SELECT DATEDIFF(MONTH, '2015-05-01', '2015-06-01') -- answer = 1
SELECT DATEDIFF(MONTH, '2015-05-01', '2015-07-01') -- 2
SELECT DATEDIFF(MONTH, '2015-05-01', '2015-08-01') -- 3
SELECT DATEDIFF(MONTH, '2015-05-01', '2015-09-01') -- 4

我们想忽略六月和七月,所以我们喜欢这些答案看起来像这样:

SELECT DATEDIFF(MONTH, '2015-05-01', '2015-06-01') -- answer = 1
SELECT DATEDIFF(MONTH, '2015-05-01', '2015-07-01') -- 1
SELECT DATEDIFF(MONTH, '2015-05-01', '2015-08-01') -- 1
SELECT DATEDIFF(MONTH, '2015-05-01', '2015-09-01') -- 2

实现这一目标的最简单方法是什么?我想要一个纯SQL解决方案,而不是使用TSQL的东西,但编写NOSUMMER_DATEDIFF之类的自定义函数也可以。

另外,请记住报告将跨越多年,因此解决方案应该能够处理。

2 个答案:

答案 0 :(得分:2)

如果您只对月份差异感兴趣,那么我会在这里提出一个技巧。计算自某个日期0起的月数,但忽略夏季月份。例如:

'2015-05-01' --> 2015 * 10 + 5 = 20155
'2015-06-01' --> 2015 * 10 + 6 = 20156
'2015-07-01' --> 2015 * 10 + 6 = 20156
'2015-08-01' --> 2015 * 10 + 6 = 20156
'2015-09-01' --> 2015 * 10 + 7 = 20157

这是一个相当简单的计算:

select (case when month(date2) <= 6 then  year(date2) * 10 + month(date2)
             when month(date2) in (7, 8) then year(date2) * 10 + 6
             else year(date2) * 10 + (month(date2) - 2)
        end)

区别对待:

select ((case when month(date2) <= 6 then  year(date2) * 10 + month(date2)
              when month(date2) in (7, 8) then year(date2) * 10 + 6
              else year(date2) * 10 + (month(date2) - 2)
         end) -
        (case when month(date1) <= 6 then  year(date1) * 10 + month(date1)
              when month(date1) in (7, 8) then year(date1) * 10 + 6
              else year(date1) * 10 + (month(date1) - 2)
         end)
       )

答案 1 :(得分:1)

为了实现这一目标,你必须&#34;分裂&#34;日期范围为&#34;数组&#34;每个日期范围的日期。 CTE在这种情况下可能会有所帮助。

请参阅:

--your table which holds dates ranges
DECLARE @dates TABLE(id INT IDENTITY(1,1), dFrom DATE, dTo DATE)
INSERT INTO @dates (dFrom, dTo)
VALUES('2015-05-01', '2015-06-01'),
('2015-05-01', '2015-07-01'),
('2015-05-01', '2015-08-01'),
('2015-05-01', '2015-09-01')

--summer month table
DECLARE @summermonths TABLE(summMonth INT)
INSERT INTO @summermonths(summMonth)
VALUES(6), (7)

--here Common Table Expressions is in action to "split" dates ranges to an array of dates for every single date range
;WITH CTE AS
(
    SELECT id, DATEADD(MM, 0, dFrom) AS ndFrom, dTo, CASE WHEN MONTH(DATEADD(MM, 0, dFrom)) = 6 OR MONTH(DATEADD(MM, 0, dFrom)) = 7 THEN 0 ELSE 1 END AS COfMonth  
    FROM @dates 
    WHERE DATEADD(MM, 1, dFrom)<=dTo
    UNION ALL
    SELECT id, DATEADD(MM, 1, ndFrom)  AS ndFrom,  dTo, CASE WHEN MONTH(DATEADD(MM, 1, ndFrom)) = 6 OR MONTH(DATEADD(MM, 1, ndFrom)) = 7 THEN 0 ELSE 1 END AS COfMonth
    FROM CTE
    WHERE DATEADD(MM, 1, ndFrom)<=dTo
) 
SELECT t1.id, t2.dFrom, t2.dTo, SUM(t1.COfMonth) AS MyDateDiff 
FROM CTE AS t1 INNER JOIN @dates AS t2 ON t1.id = t2.id 
GROUP BY t1.id, t2.dFrom , t2.dTo

结果:

id  dFrom       dTo         MyDateDiff
1   2015-05-01  2015-06-01  1
2   2015-05-01  2015-07-01  1
3   2015-05-01  2015-08-01  2
4   2015-05-01  2015-09-01  3 --not 2, because of 5, 8, 9

知道了吗?

注意:如果dFrom并且dTo不是第一个月的日期,则解决方案可能会有所不同。