I have a table with a few million entries, so I need a solution that can work on a bunch of different scenarios as most solutions I have found is only for a few iterations at best.
I have a PERIOD_FROM and a PERIOD_TO status check, aka how long the account has been in this state. It is no problem to split a two month difference but quite a few of the entries are for accounts that have paid in advance so their status will not change for up to 2 years.
The original table simplified looks something like this:
ID PERIOD_FROM PERIOD_TO DAYS
---------------------------------------------------------
115052454 02/04/2019 01/04/2021 730
115678935 06/04/2021 05/04/2023 729
119040627 06/04/2021 05/04/2023 729
115005487 01/04/2019 29/03/2021 728
116414279 17/04/2019 09/04/2021 723
116411046 17/04/2019 04/04/2021 718
116693271 24/04/2019 04/04/2021 711
123935704 05/07/2019 29/05/2021 694
119040627 16/05/2019 05/04/2021 690
115976183 02/05/2019 01/03/2021 669
What I have done for the two month difference solution is create a concat as follows:
CASE WHEN CONCAT(DATEPART(YYYY, [PERIOD_FROM]), FORMAT([PERIOD_FROM], 'MM')) = CONCAT(DATEPART(YYYY, [PERIOD_TO]), FORMAT([PERIOD_TO], 'MM'))
THEN CONCAT(DATEPART(YYYY, [PERIOD_FROM]), FORMAT([PERIOD_FROM], 'MM'))
ELSE CONCAT(DATEPART(YYYY, [PERIOD_FROM]), FORMAT([PERIOD_FROM], 'MM'), ',', DATEPART(YYYY, [PERIOD_TO]), FORMAT([PERIOD_TO], 'MM'))
END AS Period_Of
Using cross apply with string_split I can then split the line into two and using another case statement I can assign the full values based on if the period from/to is equal or greater than the split value, but this only works for a two month difference and I need up to 48 months.
I require an output that would look something like this:
ID PERIOD_FROM PERIOD_TO DAYS
------------------------------------------------------
1150524545 02/04/2019 30/04/2019 730
1150524545 01/05/2019 31/05/2019 730
1150524545 01/06/2019 30/06/2019 730
1150524545 01/07/2019 31/07/2019 730
………… ………… ………… ……
1150524545 01/02/2021 28/02/2021 730
1150524545 01/03/2021 31/03/2021 730
1150524545 01/04/2021 01/04/2021 730
Any help would be greatly appreciated!
UPDATE:
Thanks to the help of Serg, I have a solution. I tweaked it slightly so that the Period_To ends on the last date but had not specified that in my request as it was not a main concern.
Using table of numbers
-- Generate table of 1000 numbers starting 0
with t0(n) as (
select n
from (
values (1),(2),(3),(4),(5),(6),(7),(8),(9),(10)
) t(n)
),nmbs as(
select row_number() over(order by t1.n) - 1 n
from t0 t1, t0 t2, t0 t3
)
--
select Id
, dateadd(mm, nmbs.n, tbl.PERIOD_FROM) PERIOD_FROM
, case when ys.NextDate > tbl.PERIOD_TO then tbl.PERIOD_TO else ys.NextDate end PERIOD_TO
, DAYS
, tbl.PERIOD_TO originalPERIOD_TO
from [my table] tbl
join nmbs
on dateadd(mm, nmbs.n, tbl.PERIOD_FROM) <= tbl.PERIOD_TO
cross apply (select dateadd(mm, nmbs.n + 1, tbl.PERIOD_FROM) NextDate) ys
order by ID, dateadd(mm, nmbs.n, tbl.PERIOD_FROM);
The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.