Дополнить интервалы дат и заполнить предыдущими значениями

Дана таблица

if object_id('tempdb..#Test') is not null drop table #TEST
   create table #Test(datephysical datetime, Price int)

insert #TEST values ('2019-12-31 00:00:00.000',100),('2020-08-31 00:00:00.000',200),('2021-08-31 00:00:00.000',300)

введите сюда описание изображения

Необходимо дополнить недостающие даты и заполнить значения поля Price текущим значением по дате. Т.е. должно получиться следующее:

введите сюда описание изображения

Что нужно поправить в рекурсии?

;with cost as (Select DATEPHYSICAL, price, lead(DATEPHYSICAL) over(order by datephysical) leaddate
                from #test )        

, rec  as (
  SELECT distinct DATEPHYSICAL, price, leaddate 
                from cost           

    
    UNION ALL
  
  SELECT DATEADD(month, 1 ,DATEPHYSICAL), price, leaddate 
    FROM rec p
   WHERE DATEPHYSICAL <= leaddate
)
SELECT *
  FROM rec
  order by DATEPHYSICAL

Ответы (3 шт):

Автор решения: Akina
CREATE TABLE test (
  datecolumn DATE,
  valuecolumn INT
);
INSERT INTO test VALUES 
  ( '2023-01-01', 1 ),
  ( '2023-01-02', 2 ),
  ( '2023-01-05', 3 ),
  ( '2023-01-07', 4 );
WITH
cte AS (
        SELECT datecolumn, valuecolumn, LEAD(datecolumn) OVER (ORDER BY datecolumn) nextdate
        FROM test
    UNION ALL
        SELECT DATEADD(day, 1, datecolumn), valuecolumn, nextdate
        FROM cte
        WHERE DATEADD(day, 1, datecolumn) < nextdate
        )
SELECT datecolumn, valuecolumn
FROM cte 
ORDER BY 1
datecolumn valuecolumn
2023-01-01 1
2023-01-02 2
2023-01-03 2
2023-01-04 2
2023-01-05 3
2023-01-06 3
2023-01-07 4

fiddle

Если за какую-то дату имеется более одной записи, то "размножена" будет случайная из них. Если нужна определённая - нужно расширить выражение сортировки в оконной функции.

→ Ссылка
Автор решения: earl11
WITH cost AS (SELECT DATEPHYSICAL, price, lead(DATEPHYSICAL, 1, DATEPHYSICAL) OVER(ORDER BY datephysical) leaddate
                FROM #test )        
 
, rec  AS (
  SELECT DISTINCT DATEPHYSICAL, price, leaddate 
                FROM cost           
 
    
    UNION ALL
  
  SELECT dt.next_date, price, leaddate 
    FROM rec p
    cross apply (select cast(eomonth(DATEADD(MONTH, 1 ,DATEPHYSICAL)) as datetime)) as dt(next_date)
   WHERE dt.next_date < leaddate
)
SELECT *
  FROM rec
  ORDER BY DATEPHYSICAL;
→ Ссылка
Автор решения: ValNik

Посмотрите пример

with r as(
  select datephysical,price
     ,lead(datephysical)over(order by datephysical) nextdate
  from test
  union all
  select eomonth(dateadd(month,1,datephysical)),price, nextdate
  from r
  where eomonth(dateadd(month,1,datephysical))<nextdate
)
select * from r
order by datephysical
→ Ссылка