Reputation: 7180
Quick setup that can be used in a fiddle.
create table tbl
(avgdate date, avgvalue numeric(10,2));
insert into tbl values ('2021-01-01',10.4);
insert into tbl values ('2021-01-02',13.1);
insert into tbl values ('2021-01-03',11.35);
insert into tbl values ('2021-01-04',3.4);
insert into tbl values ('2021-01-05',7.12);
insert into tbl values ('2021-01-06',16.76);
insert into tbl values ('2021-01-07',17.2);
insert into tbl values ('2021-01-08',13.76);
insert into tbl values ('2021-01-09',10.56);
insert into tbl values ('2021-01-10',null);
insert into tbl values ('2021-01-11',null);
insert into tbl values ('2021-01-12',null);
I'm looking to write something along the lines of
select avgdate,
case when avgvalue is not null then avgvalue
else
--avg of past 7 days
end
from tbl
Normally I'd use the lag function or rownumber to pick out the previous rows values and average them which works for the 10th, but my logic hits a bug when it needs to include calculated rows. Jan 12th should be the average values for 5th through 9th, plus the calculated values for the 10th and 11th.
Upvotes: 0
Views: 829
Reputation: 1269873
This is pretty much the code you want:
coalesce(avgvalue,
avg(avgvalue) over (order by date rows between 7 preceding and 1 preceding)
)
Wait. That chooses the previous 7 values some of which might be NULL
. You can use apply
for this purpose:
select t.*,
coalesce(t.avgvalue, t2.avgvalue7)
from tbl t outer apply
(select avg(t2.avgvalue) as avgvalue7
from (select top (7) t2.avgvalue
from tbl t2
where t2.avgvalue is not null and
t2.date < t.date
order by t2.date desc
) t2
) t2;
Upvotes: 1