When I execute query
SELECT Item,
[From date],
[To date]
from ItemDate;
I got this table:
('A1','2014-03-05','2014-07-21'),
('A1','2014-07-25','2015-03-15'),
('A1','2015-03-17','2016-03-17'),
('B1','2015-04-18','2016-06-16'),
('C1','2015-04-21','2016-02-12'),
('C1','2016-02-14','2016-08-29')
I want to calculate difference between date [From date]
and [To date]
and get next table:
Item Year NoOfMonth NoOfDays
A1 2014 9 ...
A1 2015 ... ...
........
Group by Year and item
NoOfMonts
is number of months by year and item
NoOfDays
is number of days by year and item.
Any idea?
You can use calendar table and some date functions:
;WITH calendar AS (
SELECT CAST(MIN([From date]) as datetime) as d,
MAX([To date]) as e
FROM ItemTable
UNION ALL
SELECT DATEADD(day,1,d),
e
FROM calendar
WHERE d < e
), cte AS(
SELECT i.Item,
DATEPART(year,c.d) as [Year],
DATEDIFF(month,MIN(c.d),MAX(c.d)) as NoOfMonth,
DATEDIFF(day,DATEADD(month,DATEDIFF(month,MIN(c.d),MAX(c.d)),MIN(c.d)),MAX(c.d)) as NoOfDays
FROM ItemTable i
INNER JOIN calendar c
ON c.d between i.[From date] and i.[To date]
GROUP BY i.Item, DATEPART(year,c.d),[From date],[To date]
)
SELECT Item,
[Year],
SUM(NoOfMonth) as NoOfMonth,
SUM(NoOfDays) as NoOfDays
FROM cte
GROUP BY Item,[Year]
ORDER BY Item
OPTION (MAXRECURSION 0)
Output:
Item Year NoOfMonth NoOfDays
A1 2014 9 22
A1 2015 11 28
A1 2016 2 16
B1 2015 8 13
B1 2016 5 15
C1 2015 8 10
C1 2016 7 26
EDIT
Inspired by this question.
SELECT Item,
[Year],
CASE WHEN SUM(NoOfDays) < 0 THEN SUM(NoOfMonth)-1
WHEN SUM(NoOfDays) > 30 THEN SUM(NoOfMonth)+1
ELSE SUM(NoOfMonth) END as NoOfMonth,
CASE WHEN SUM(NoOfDays) >= 30 THEN SUM(NoOfDays)-30
WHEN SUM(NoOfDays) < 0 THEN SUM(NoOfDays)+30
ELSE SUM(NoOfDays) END as NoOfDays
FROM cte
GROUP BY Item,[Year]
ORDER BY Item
OPTION (MAXRECURSION 0)
The main problem of such report - it is hard to define what is 1 month, DATEDIFF just takes number from 2 dates and subtract one from another.
I have choose 30 as a days count in month, and now I compare values of days with 30 so we can add +1
to month if the day count goes under zero or below 30