Арифметика даты для этой проблемы довольно запутанная.Похоже, вы подсчитываете месяцы, и мне трудно, когда вы используете дату окончания квартала.
Поэтому ниже добавлена одна дата для переноса значений в следующий месяц.Это только для вычисления, но оно упрощает логику разделения.
WITH cte AS (
SELECT id, sd.from_date as within_quarter_start_date,
(CASE WHEN quarter_end < to_date THEN quarter_end ELSE to_date END) as within_quarter_end_date,
DATEADD(quarter, DATEDIFF(QUARTER, 0, from_date), 0) as quarter_start,
v.quarter_end,
DATEADD(day, 1, sd.to_date) as to_date,
sd.value, 1 as lev
FROM datatable sd CROSS APPLY
(VALUES (DATEADD(QUARTER, DATEDIFF(QUARTER, 0, from_date) + 1, 0))) v(quarter_end)
UNION ALL
SELECT id, CONVERT(DATE, DATEADD(quarter, 1, quarter_start)),
(CASE WHEN DATEADD(quarter, 1, quarter_end) < to_date THEN DATEADD(quarter, 1, quarter_end) ELSE to_date END) as within_quarter_end_date,
DATEADD(quarter, 1, quarter_start),
DATEADD(quarter, 1, quarter_end),
to_date,
value, lev + 1
FROM cte
WHERE quarter_end < to_date and lev < 10
)
select within_quarter_start_date as from_date,
dateadd(day, -1, within_quarter_end_date) as to_date,
value * (datediff(month, within_quarter_start_date, within_quarter_end_date) ) / 3.0,
quarter_start, quarter_end
from cte
order by 1, 2;
Здесь - это db <> скрипка.