我们正在为季节性业务运行报告,预计夏季将会出现平静期。对于某些指标,我们基本上想假装那些月份甚至不存在。
因此,请考虑以下的默认行为:
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
之类的自定义函数也可以。
另外,请记住报告将跨越多年,因此解决方案应该能够处理。
答案 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
不是第一个月的日期,则解决方案可能会有所不同。