Заполните пропущенные даты на основе мин и макс в SAS - PullRequest
0 голосов
/ 03 мая 2018

У меня есть набор данных, подобный приведенному ниже, мне интересно, как я могу заполнить эти пропущенные даты в SAS.

  1. Отсутствует FROM_NEW (2-я строка)

    Сначала найдите TO_NEW (14NOV2016) в последнем ряду TOS = "FAC_IP" в том же ADM. Затем выполните цикл в PRO_IP, чтобы найти мин. (Дата), но больше (> 14NOV2016), чтобы заменить отсутствующий FROM_NEW, который 20NOV2016 должен быть заполнен.

  2. Отсутствует TO_NEW (строка 25)

    Сначала найдите FROM_NEW (14DEC2016) в последнем ряду TOS = "FAC_IP"
    Затем выполните цикл в PRO_IP, чтобы найти максимальное значение (дата), но меньше (<14 декабря 2016 г.), чтобы заменить отсутствующий TO_NEW, который <strong>08DEC2016 должен быть заполнен.

    Obs     MEMNUM       ADM    LINE   FROM      TO     FROM_NEW   TO_NEW   TOS  order 
    1  9840964190000001 237696870 X 23OCT2016 23NOV2016 23OCT2016 30OCT2016 FAC_IP 1 
    2  9840964190000001 237696870 R 23OCT2016 23NOV2016 .         23NOV2016 FAC_IP 2 
    3  9840964190000001 237696870 X 23OCT2016 23NOV2016 02NOV2016 03NOV2016 FAC_IP 3 
    4  9840964190000001 237696870 X 23OCT2016 23NOV2016 05NOV2016 09NOV2016 FAC_IP 4 
    5  9840964190000001 237696870 X 23OCT2016 23NOV2016 11NOV2016 14NOV2016 FAC_IP 5 
    6  9840964190000001 237696870   23OCT2016 23NOV2016 25OCT2016 25OCT2016 PRO_IP . 
    7  9840964190000001 237696870   23OCT2016 23NOV2016 26OCT2016 26OCT2016 PRO_IP . 
    8  9840964190000001 237696870   23OCT2016 23NOV2016 27OCT2016 27OCT2016 PRO_IP . 
    9  9840964190000001 237696870   23OCT2016 23NOV2016 28OCT2016 28OCT2016 PRO_IP . 
    10 9840964190000001 237696870   23OCT2016 23NOV2016 29OCT2016 29OCT2016 PRO_IP . 
    11 9840964190000001 237696870   23OCT2016 23NOV2016 30OCT2016 30OCT2016 PRO_IP . 
    12 9840964190000001 237696870   23OCT2016 23NOV2016 02NOV2016 02NOV2016 PRO_IP . 
    13 9840964190000001 237696870   23OCT2016 23NOV2016 03NOV2016 03NOV2016 PRO_IP . 
    14 9840964190000001 237696870   23OCT2016 23NOV2016 06NOV2016 06NOV2016 PRO_IP . 
    15 9840964190000001 237696870   23OCT2016 23NOV2016 07NOV2016 07NOV2016 PRO_IP . 
    16 9840964190000001 237696870   23OCT2016 23NOV2016 08NOV2016 08NOV2016 PRO_IP . 
    17 9840964190000001 237696870   23OCT2016 23NOV2016 11NOV2016 11NOV2016 PRO_IP . 
    18 9840964190000001 237696870   23OCT2016 23NOV2016 12NOV2016 12NOV2016 PRO_IP . 
    19 9840964190000001 237696870   23OCT2016 23NOV2016 13NOV2016 13NOV2016 PRO_IP . 
    20 9840964190000001 237696870   23OCT2016 23NOV2016 14NOV2016 14NOV2016 PRO_IP . 
    21 9840964190000001 237696870   23OCT2016 23NOV2016 20NOV2016 20NOV2016 PRO_IP . 
    22 9840964190000001 237696870   23OCT2016 23NOV2016 21NOV2016 21NOV2016 PRO_IP . 
    23 9840964190000001 237696870   23OCT2016 23NOV2016 22NOV2016 22NOV2016 PRO_IP . 
    24 9840964190000001 237696870   23OCT2016 23NOV2016 23NOV2016 23NOV2016 PRO_IP . 
    25 9840964190000001 244243815 R 04DEC2016 17DEC2016 04DEC2016 .         FAC_IP 1 
    26 9840964190000001 244243815 X 04DEC2016 17DEC2016 14DEC2016 17DEC2016 FAC_IP 2 
    27 9840964190000001 244243815   04DEC2016 17DEC2016 04DEC2016 04DEC2016 PRO_IP . 
    28 9840964190000001 244243815   04DEC2016 17DEC2016 05DEC2016 05DEC2016 PRO_IP . 
    29 9840964190000001 244243815   04DEC2016 17DEC2016 06DEC2016 06DEC2016 PRO_IP . 
    30 9840964190000001 244243815   04DEC2016 17DEC2016 07DEC2016 07DEC2016 PRO_IP . 
    31 9840964190000001 244243815   04DEC2016 17DEC2016 08DEC2016 08DEC2016 PRO_IP . 
    32 9840964190000001 244243815   04DEC2016 17DEC2016 14DEC2016 14DEC2016 PRO_IP . 
    33 9840964190000001 244243815   04DEC2016 17DEC2016 15DEC2016 15DEC2016 PRO_IP . 
    34 9840964190000001 244243815   04DEC2016 17DEC2016 16DEC2016 16DEC2016 PRO_IP . 
    35 9840964190000001 244243815   04DEC2016 17DEC2016 17DEC2016 17DEC2016 PRO_IP . 
    

Ответы [ 2 ]

0 голосов
/ 04 мая 2018

Вам потребуется использовать вложенные подзапросы или использовать функциональность SAS Retain на шаге данных, чтобы выполнить это.

Решение ниже использует подзапросы, см. Мои встроенные комментарии:

data have;
/* infile datalines dlm=',' dsd;  */
length Obs 8.    MEMNUM  $22.     ADM  $9.  LINE $1.   FROM   8.     TO   8.    FROM_NEW 8.    TO_NEW  8.   TOS $6. order  8. ;
format FROM   date9.     TO   date9.    FROM_NEW  date9.    TO_NEW  date9. ;
informat FROM   date9.     TO   date9.    FROM_NEW  date9.    TO_NEW  date9. ;
input 
Obs     MEMNUM  $     ADM  $  LINE $   FROM      TO     FROM_NEW   TO_NEW   TOS $ order ;
datalines; 
1  9840964190000001 237696870 X 23OCT2016 23NOV2016 23OCT2016 30OCT2016 FAC_IP 1 
2  9840964190000001 237696870 R 23OCT2016 23NOV2016 .         23NOV2016 FAC_IP 2 
3  9840964190000001 237696870 X 23OCT2016 23NOV2016 02NOV2016 03NOV2016 FAC_IP 3 
4  9840964190000001 237696870 X 23OCT2016 23NOV2016 05NOV2016 09NOV2016 FAC_IP 4 
5  9840964190000001 237696870 X 23OCT2016 23NOV2016 11NOV2016 14NOV2016 FAC_IP 5 
6  9840964190000001 237696870 .  23OCT2016 23NOV2016 25OCT2016 25OCT2016 PRO_IP . 
7  9840964190000001 237696870 .  23OCT2016 23NOV2016 26OCT2016 26OCT2016 PRO_IP . 
8  9840964190000001 237696870 .  23OCT2016 23NOV2016 27OCT2016 27OCT2016 PRO_IP . 
9  9840964190000001 237696870 .  23OCT2016 23NOV2016 28OCT2016 28OCT2016 PRO_IP . 
10 9840964190000001 237696870 .  23OCT2016 23NOV2016 29OCT2016 29OCT2016 PRO_IP . 
11 9840964190000001 237696870 .  23OCT2016 23NOV2016 30OCT2016 30OCT2016 PRO_IP . 
12 9840964190000001 237696870 .  23OCT2016 23NOV2016 02NOV2016 02NOV2016 PRO_IP . 
13 9840964190000001 237696870 .  23OCT2016 23NOV2016 03NOV2016 03NOV2016 PRO_IP . 
14 9840964190000001 237696870 . 23OCT2016 23NOV2016 06NOV2016 06NOV2016 PRO_IP . 
15 9840964190000001 237696870 .  23OCT2016 23NOV2016 07NOV2016 07NOV2016 PRO_IP . 
16 9840964190000001 237696870 .  23OCT2016 23NOV2016 08NOV2016 08NOV2016 PRO_IP . 
17 9840964190000001 237696870 .  23OCT2016 23NOV2016 11NOV2016 11NOV2016 PRO_IP . 
18 9840964190000001 237696870 .  23OCT2016 23NOV2016 12NOV2016 12NOV2016 PRO_IP . 
19 9840964190000001 237696870 .  23OCT2016 23NOV2016 13NOV2016 13NOV2016 PRO_IP . 
20 9840964190000001 237696870 .  23OCT2016 23NOV2016 14NOV2016 14NOV2016 PRO_IP . 
21 9840964190000001 237696870 .  23OCT2016 23NOV2016 20NOV2016 20NOV2016 PRO_IP . 
22 9840964190000001 237696870 .  23OCT2016 23NOV2016 21NOV2016 21NOV2016 PRO_IP . 
23 9840964190000001 237696870 .  23OCT2016 23NOV2016 22NOV2016 22NOV2016 PRO_IP . 
24 9840964190000001 237696870 .  23OCT2016 23NOV2016 23NOV2016 23NOV2016 PRO_IP . 
25 9840964190000001 244243815 R 04DEC2016 17DEC2016 04DEC2016 .         FAC_IP 1 
26 9840964190000001 244243815 X 04DEC2016 17DEC2016 14DEC2016 17DEC2016 FAC_IP 2 
27 9840964190000001 244243815 .  04DEC2016 17DEC2016 04DEC2016 04DEC2016 PRO_IP . 
28 9840964190000001 244243815 .  04DEC2016 17DEC2016 05DEC2016 05DEC2016 PRO_IP . 
29 9840964190000001 244243815 .  04DEC2016 17DEC2016 06DEC2016 06DEC2016 PRO_IP . 
30 9840964190000001 244243815 .  04DEC2016 17DEC2016 07DEC2016 07DEC2016 PRO_IP . 
31 9840964190000001 244243815 .  04DEC2016 17DEC2016 08DEC2016 08DEC2016 PRO_IP . 
32 9840964190000001 244243815 .  04DEC2016 17DEC2016 14DEC2016 14DEC2016 PRO_IP . 
33 9840964190000001 244243815 .  04DEC2016 17DEC2016 15DEC2016 15DEC2016 PRO_IP . 
34 9840964190000001 244243815 .  04DEC2016 17DEC2016 16DEC2016 16DEC2016 PRO_IP . 
35 9840964190000001 244243815 .  04DEC2016 17DEC2016 17DEC2016 17DEC2016 PRO_IP . 
;
run;
proc sql; 
create table  missing_dates as
select MEMNUM , ADM , FROM_NEW , TO_NEW , MAX_FROM_NEW , Max_TO_NEW ,
max(FNL)  as FNL format=date9., min(TNL) as TNL format=date9. 
from (
    select t1.*, t2.Max_Order, t3.FROM_NEW as MAX_FROM_NEW , t3.TO_NEW as Max_TO_NEW ,
    t4.FROM_NEW as FNL, t4.TO_NEW as TNL
    from 
/*  Identify Missing dates*/
    (select * from have where FROM_NEW = . or TO_NEW=.) as t1
    left join 
/*  Identify Max order */
    (select MEMNUM, ADM, max(order)  as Max_Order 
    from have where TOS='FAC_IP' group by MEMNUM, ADM ) as t2 on t1.MEMNUM=t2.MEMNUM and t1.ADM = t2.ADM
/*  Join Max Order with the rest of the Data */
    inner join have as t3 on t3.TOS='FAC_IP' and t3.MEMNUM=t2.MEMNUM and t3.ADM = t2.ADM and t3.order=t2.Max_Order
/*  Join Max Order with PRO_IP */
    left join
    (select  MEMNUM, ADM, FROM_NEW , TO_NEW from have where TOS='PRO_IP' group by MEMNUM, ADM ) as t4 on t1.MEMNUM=t4.MEMNUM and t1.ADM = t4.ADM
) as want 
where case when (FROM_NEW=. and TNL> Max_TO_NEW) then 1
when (TO_NEW=. and FNL  < MAX_FROM_NEW) then 1
else 0
end
group by MEMNUM , ADM , FROM_NEW , TO_NEW , MAX_FROM_NEW , Max_TO_NEW  
; 
quit;

proc sql;
 create table update_mising as select 
A.Obs, A.MEMNUM, A.ADM  , A.LINE ,A.FROM , A.TO   , 
coalesce(A.FROM_NEW,B.TNL) as FROM_NEW format=date9.  , 
coalesce(A.TO_NEW,B.TNL) as TO_NEW format=date9. ,
 A.TOS , A.order 
from have  A left join missing_dates B
on (A.FROM_NEW = . or A.TO_NEW=.) and A.MEMNUM=B.MEMNUM and A.ADM = B.ADM
order by A.OBS
;
quit;

Финальный стол:

Output

0 голосов
/ 04 мая 2018

Итак, вот как вы можете обновить FROM_NEW в макросе sas. Это довольно явно, и вы должны быть в состоянии создать свой собственный макрос для TO_NEW. Если вам нужна дополнительная помощь, вернитесь с тем, что вы уже пробовали, и мы можем перейти оттуда. Убедитесь, что все ваши даты являются действительными датами sas, а не литералами в наборе данных

*create file of all needed from_new dates
proc sql noprint;
create table needed_FN as
select distinct adm,order as row from test where from_new = .;quit;

* find out how many we have
proc sql noprint;
select count(*) into: cnt from needed_fn;quit;

*create macro to loop through
%macro test;
%do i = 1 %to &cnt;

   *for each needed from_new date place the adm and order number into macro vars
   proc sql noprint;
    select ADM,row into: adm, :row  from needed_FN where monotonic()=&i;quit;

   * create temp table for specific adm
   proc sql noprint;
    create table work as 
     select * from test where adm = &adm;quit;

   * find out how many 'FAC_IP's we have
   proc sql noprint;
    select max(order)into:maxOrder from work;quit;

   * get the checkdate
   proc sql noprint;
    select (TO_NEW) format=date9. into:checkDate  from work where ORDER= &maxOrder;

   *create temp table of all PRO_iP dates > checkDate
   proc sql noprint;
    create table proDates as
     select * from work where TOS='PRO_IP' and FROM_NEW > "&checkDate"d;quit;

   * get the smallest one
   proc sql noprint;
    select min(From_new)format date9. into:replaceDate from prodates;quit;

   *update the table
   proc sql;
    update test
      set from_new = "&replaceDate"d
          where adm = &adm
          and order = &row;   
%end;
%mend test;
%test;
...