First create this number table if you don't have one already
SELECT TOP 10000 N=IDENTITY(INT, 0, 1)
INTO dbo.Numbers
FROM master.dbo.syscolumns a CROSS JOIN master.dbo.syscolumns b;
ALTER TABLE dbo.Numbers ADD CONSTRAINT NBR_pk PRIMARY KEY(N);
;with cte(id, Months) as (
select id, STRING_AGG(format(dateadd(m,n.n,StartDate),'MMM'),',')
from offertest o cross join dbo.Numbers n
where dateadd(m,n.n,StartDate)<=isnull(EndDate, '20211231')
group by id)
select o.StartDate,o.EndDate,c.Months
from cte c inner join offertest o on o.id=c.id
TEST
http://sqlfiddle.com/#!18/626e3/1
You can replace '20211231' with getdate()
or other limit date
EDIT
You can create the numbers table as a tempt table just by adding #
SELECT TOP 10000 N=IDENTITY(INT, 0, 1)
INTO #Numbers
FROM master.dbo.syscolumns a CROSS JOIN master.dbo.syscolumns b;
ALTER TABLE #Numbers ADD CONSTRAINT NBR_pk PRIMARY KEY(N);
Regarding using the query as subquery, there is no need, just use it as a CTE like this:
;with cte(id, Months) as (
select id, STRING_AGG(format(dateadd(m,n.n,StartDate),'MMM'),',')
from offertest o cross join #Numbers n
where dateadd(m,n.n,StartDate)<=isnull(EndDate, '20211231')
group by id)
,months(StartDate,EndDate,Months) as (
select o.StartDate,o.EndDate,c.Months
from cte c inner join offertest o on o.id=c.id)
Select 'your query here joining Months'