2

I'm looking for you, SQL Experts (or maybe this is a quite easy problem, than of course everyone is welcome :) )

I start with the following table:

ID|Contract Start Date|Runtime (Months)|MonthCount
1 |2015-04-01         |48              |1
2 |2018-02-01         |36              |1

I want to create a table which creates (inserts) new rows based on the recoreds in the column Contract Start Date and Runtime. In other words I need to create a row for each month starting from the startdate unitl the number of runtime is reached.

ID|Contract Start Date|Runtime (Months)|MonthCount
1 |2015-04-01         |48              |1
1 |2015-05-01         |48              |1
1 |2019-04-01         |48              |48
2 |2018-02-01         |36              |1
2 |2018-03-01         |36              |2
2 |2021-03-01         |36              |36

I tried achiving this with nested cursor and while loops, this works somehow; 'the only issue' is, that I create a cartesian product/duplicate records.

While researching I found this: While loop creating duplicate records; but I'm not shure how to apply this to my code

SQL:

DECLARE @ID INT
DECLARE @ContractStartDate DATE
DECLARE @ContractRuntime INT
DECLARE @MonthCount INT




 --Declaring Cursor
 DECLARE MonthCursor CURSOR 
    FOR SELECT * FROM LeasingData

OPEN MonthCursor


    FETCH NEXT FROM MonthCursor
        INTO @ID,@ContractStartDate, @ContractRuntime, @MonthCount

    WHILE @@FETCH_STATUS = 0
        BEGIN 

        WHILE @MonthCount < @ContractRuntime
            BEGIN
            SET @MonthCount = @MonthCount + 1
            SET @ContractStartDate = DATEADD(month, 1, @ContractStartDate)

            INSERT INTO Table
            SELECT @ID,@ContractStartDate, @ContractRuntime, @MonthCount

            END

        FETCH NEXT FROM MonthCursor
            INTO @ID,@ContractStartDate, @ContractRuntime, @MonthCount

        END

CLOSE MonthCursor
DEALLOCATE MonthCursor

This results in:

ID|Contract Start Date|Runtime (Months)|MonthCount
1 |2015-04-01         |48              |1
1 |2015-05-01         |48              |2
1 |2015-06-01         |48              |3
1 |2015-06-01         |48              |3
1 |2015-06-01         |48              |3
1 |2015-06-01         |48              |3
1 |2015-07-01         |48              |4
1 |2015-07-01         |48              |4
1 |2015-07-01         |48              |4
1 |2015-07-01         |48              |4
1 |2015-07-01         |48              |4
1 |2015-07-01         |48              |4

and so on....

Maybe I'm completly on the wrong path with my solution. Glad to learn something new :)

1
  • A WHILE loop is most definitely the worst way to do this, I'm afraid. A Tally table would be a far better option. Commented Aug 7, 2019 at 15:11

1 Answer 1

1

Use a recursive CTE:

with cte as (
      select id, contract_start_date, runtime, monthcount
      from t
      union all
      select id, dateadd(month, monthcount, contract_start_date), runtime - 1, monthcount
      from cte
      where runtime > 0
    )
select *
from cte
order by id, contract_start_date;

If you need more than 100 months, add option (maxrecursion 0).

Sign up to request clarification or add additional context in comments.

1 Comment

Hi @gordon-linoff, thank you for pointing me in this direction. Will try this!

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.