I have a data set as periodic. However, these periods are not consecutive. My data pattern is like that
Period Customer_No Date Product
1 111 01.01.2017 X
3 111 05.09.2017 Y
8 111 02.05.2018 Z
6 222 02.02.2017 X
9 222 06.04.2017 Z
12 222 05.09.2018 B
15 222 02.01.2019 A
End of the period should be 15 for all customers. I want to create consecutive periods based on customers and fill them with previous data like below:
Period Customer_No Date Product
1 111 01.01.2017 X
2 111 01.01.2017 X
3 111 05.09.2017 Y
4 111 05.09.2017 Y
5 111 05.09.2017 Y
6 111 05.09.2017 Y
7 111 05.09.2017 Y
8 111 02.05.2018 Z
9 111 02.05.2018 Z
10 111 02.05.2018 Z
11 111 02.05.2018 Z
12 111 02.05.2018 Z
13 111 02.05.2018 Z
14 111 02.05.2018 Z
15 111 02.05.2018 Z
6 222 02.02.2017 X
7 222 02.02.2017 X
8 222 02.02.2017 X
9 222 06.04.2017 Z
10 222 06.04.2017 Z
11 222 06.04.2017 Z
12 222 05.09.2018 B
13 222 05.09.2018 B
14 222 05.09.2018 B
15 222 02.01.2019 A
create table tbl_cust(period int,Customer_No int, Date date, Product varchar)
insert into tbl_cust values(1,111,'01.01.2017','X')
insert into tbl_cust values(3,111,'05.09.2017','Y')
insert into tbl_cust values(8,111,'02.05.2018','Z')
insert into tbl_cust values(6,222,'02.02.2017','X')
insert into tbl_cust values(9,222,'06.04.2017','Z')
insert into tbl_cust values(12,222,'05.09.2018','B')
insert into tbl_cust values(15,222,'02.01.2019','A')
You can use a recursive CTE to generate the rows that you want. Then you need to fill them in with the most recent data. What you really want is lag(ignore nulls), but SQL Server does not support that functionality.
There are only up to 15 rows per customer, so apply is a reasonable alternative:
with cte as (
select min(period) as period, customer_no
from tbl_cust
group by customer_no
union all
select period + 1, customer_no
from cte
where period < 15
)
select cte.period, cte.customer_no, c.date, c.product
from cte cross apply
(select top (1) c.*
from tbl_cust c
where c.customer_no = cte.customer_no and
c.period <= cte.period
order by c.period desc
) c
order by cte.customer_no, cte.period;
Here is a db<>fiddle.
You can try this.
select ID as period, Customer_No, [Date], Product from
(VALUES (1),(2),(3),(4),(5),(6),(7),(8),(9),(10),(11),(12),(13),(14),(15)) P(ID)
OUTER APPLY( SELECT *, ROW_NUMBER() OVER(PARTITION BY Customer_No ORDER BY period desc) RN
FROM tbl_cust C WHERE C.period <= P.ID ) X
WHERE X.RN = 1
ORDER BY Customer_No, ID
Result:
period Customer_No Date Product
----------- ----------- ---------- -------
1 111 2017-01-01 X
2 111 2017-01-01 X
3 111 2017-05-09 Y
4 111 2017-05-09 Y
5 111 2017-05-09 Y
6 111 2017-05-09 Y
7 111 2017-05-09 Y
8 111 2018-02-05 Z
9 111 2018-02-05 Z
10 111 2018-02-05 Z
11 111 2018-02-05 Z
12 111 2018-02-05 Z
13 111 2018-02-05 Z
14 111 2018-02-05 Z
15 111 2018-02-05 Z
6 222 2017-02-02 X
7 222 2017-02-02 X
8 222 2017-02-02 X
9 222 2017-06-04 Z
10 222 2017-06-04 Z
11 222 2017-06-04 Z
12 222 2018-05-09 B
13 222 2018-05-09 B
14 222 2018-05-09 B
15 222 2019-02-01 A
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With