Предполагается, что ваши данные отсортированы по id
и date
.
Сначала сделайте слияние на будущее (чтобы получить следующую дату):
data lookahead ;
merge have
have (firstobs=2 rename=(date=nextdate id=nextid)) ;
if id ^= nextid then call missing(nextdate) ;
drop nextid ;
run ;
/* data now looks like this */
id balance date nextdate
1 10 02Mar2018 05Mar2018
1 12 05Mar2018 07Mar2018
1 -15 07Mar2018 14Mar2018
1 14 14Mar2018 25Mar2018
1 -25 25Mar2018
ЗатемРазверните отсутствующие даты, рассматривая случаи, когда первая дата для идентификатора не является первой в месяце, а последняя запись для идентификатора не является последним днем месяца:
data expand ;
set lookahead (rename=(date=thisdate)) ;
by id ;
if first.id and day(thisdate) ^= 1 then do ;
/* loop from 1st of month to day before date, output new record for each date */
do date = intnx('month',thisdate,0,'b') to thisdate - 1 ;
output ;
end ;
end ;
/* output the input record */
date = thisdate ; output ;
/* output dates up to the next date */
if nextdate > thisdate + 1 then do ;
do date = thisdate + 1 to nextdate - 1 ;
output ;
end ;
end ;
else
/* last record for id, loop to end of month */
if missing(nextdate) and thisdate ^= intnx('month',thisdate,0,'end') then do ;
do date = thisdate + 1 to intnx('month',thisdate,0,'end') ;
output ;
end ;
end ;
drop thisdate nextdate ;
format date date9. ;
run ;
/* data now looks like this */
id balance date
1 10 01Mar2018
1 10 02Mar2018
1 10 03Mar2018
1 10 04Mar2018
1 12 05Mar2018
1 12 06Mar2018
1 -15 07Mar2018
1 -15 08Mar2018
... etc ...
1 -15 13Mar2018
1 14 14Mar2018
1 14 15Mar2018
... etc ...
1 14 24Mar2018
1 -25 25Mar2018
... etc ...
1 -25 31Mar2018
Теперь должно быть относительно легко помечать значения соответствующим образом и подсчитывать их по идентификатору / месяцу.