It's very similar to this question:
Split date range into one row per month in sql server
Although you are doing grouping by year, so based on that answer you can modify it to do what you want by adding MIN
, MAX
to your date values and grouping by the YEAR()
:
Schema Setup:
CREATE TABLE MonthSplit
([ID] varchar(2), [start_date] datetime, [end_date] datetime, [amount] int)
;
INSERT INTO MonthSplit
([ID], [start_date], [end_date], [amount])
VALUES
('a1', '2013-12-01 00:00:00', '2014-03-31 00:00:00', 100),
('a2', '2013-10-01 00:00:00', '2015-05-01 00:00:00', 400)
;
Recursive CTE to group by Year:
WITH cte AS
(SELECT ID
, start_date
, end_date
, start_date AS from_date
, DATEADD(day, day(start_date)* -1 + 1, start_date) AS first_of_month
FROM MonthSplit
UNION ALL
SELECT ID
, start_date
, end_date
, DATEADD(month,1,first_of_month)
, DATEADD(month,1,first_of_month)
FROM cte
WHERE DATEADD(month,1,from_date) < end_date
)
SELECT ID as ID,
min(start_date) as org_start_date,
min(end_date) as org_end_date,
min(from_date) AS new_start_date,
CASE when max(end_date) < DATEADD(month,1,max(first_of_month)) THEN
max(end_date)
ELSE
DATEADD(day, -1, DATEADD(month,1,max(first_of_month)))
END AS new_end_date
FROM cte
group by year(from_date), ID
Results:
| ID | ORG_START_DATE | ORG_END_DATE | NEW_START_DATE | NEW_END_DATE |
|----|-------------------|----------------|-------------------|-------------------|
| a1 | December, 01 2013 | March, 31 2014 | December, 01 2013 | December, 31 2013 |
| a1 | December, 01 2013 | March, 31 2014 | January, 01 2014 | March, 31 2014 |
| a2 | October, 01 2013 | May, 01 2015 | October, 01 2013 | December, 31 2013 |
| a2 | October, 01 2013 | May, 01 2015 | January, 01 2014 | December, 31 2014 |
| a2 | October, 01 2013 | May, 01 2015 | January, 01 2015 | April, 30 2015 |