Что вам нужно сделать, это сначала сгенерировать последовательность дат для каждого контракта / продукта, а затем использовать последовательность для группировки.
Наиболее удобный способ генерации последовательности - использовать довольно плохо документированную таблицу spt_values, например:
WITH Contracts_CTE (contract_id, product_id, contract_day, amount) AS
(
SELECT
cl.contract_id,
cl.product_id,
DATEADD(DAY, v.number, cl.contract_line_start),
cl.amount / DATEDIFF(DAY, cl.contract_line_start, cl.contract_line_end)
FROM contracts_lines cl
CROSS JOIN master.dbo.spt_values v
WHERE v.type = 'P'
AND DATEADD(DAY, v.number, cl.contract_line_start) < cl.contract_line_end
)
SELECT
DATEPART(YEAR, c.contract_day) AS contract_year,
DATEPART(MONTH, c.contract_day) AS contract_month,
c.product_id,
c.contract_id,
SUM(Amount) AS contract_amount
FROM Contracts_CTE c
GROUP BY
c.product_id,
c.contract_id,
DATEPART(YEAR, c.contract_day),
DATEPART(MONTH, c.contract_day)
Просто предостережение - числа в spt_values изменяются только от 0 до 2047, поэтому если у вас есть контракты, срок действия которых превышает 5 лет, вам нужно будет создать более длинную последовательность. Самый простой способ сделать это - CROSS JOIN присоединить таблицу spt_values к себе, т. Е .:
SELECT (v1.number * 2048) + v2.number
FROM master.dbo.spt_values v1
CROSS JOIN master.dbo.spt_values v2
WHERE v1.type = 'P'
AND v2.type = 'P'
AND ((v1.number * 2048) + v2.number) < 100000
Очевидно, вам придется интегрировать это в приведенный выше запрос, но если это действительно необходимо, то это не должно быть слишком сложно.