SAS Macro в макросе - как изменить процесс? - PullRequest
0 голосов
/ 10 ноября 2018

Вы написали, что я не должен устанавливать% macro в% macro.поэтому, пожалуйста, помогите в моем процессе.Генезис: у меня есть одна таблица, в которой хранятся все процессы SAS, которые запускаются день за днем, но различные отчеты должны выполняться в разные дни - в соответствии с полем "Nr_week_day".Если сегодня содержится в этом поле - я помещаю этот процесс в таблицу general_stock для запуска.Ниже мой код с комментариями - что я пытаюсь получить.В общем случае - этот код работает, но он с макросом в макросе.может быть, вы лучше представляете, как это работает.Этот процесс связан с моими другими «вопросами»: SAS включает динамический путь Макрос SAS в макросе

    data CONTROL_FILES_BASE;
       input  Priority : 2.
              ACTIVE: 1.
              PROCES_NAME: $10.
              Nr_week_day: $10.

    ;   cards;
    1 1 TEST_01 (1,3,6)
    2 1 TEST_02 0
    3 1 TEST_03 (4,5)
    ;

    Data Kalendariusz;
    infile cards dlm=',' dsd;
       input  ref_date: date9.
              Nr_day_of_month
              Nr_week_day
              Number_date;
        Format ref_date DDMMYY10.;
    cards;
    01NOV2018,  1,  4,  20181101
    02NOV2018,  2,  5,  20181102
    03NOV2018,  3,  6,  20181103
    04NOV2018,  4,  7,  20181104
    05NOV2018,  5,  1,  20181105
    06NOV2018,  6,  2,  20181106
    07NOV2018,  7,  3,  20181107
    08NOV2018,  8,  4,  20181108
    09NOV2018,  9,  5,  20181109
    10NOV2018,  10, 6,  20181110
    11NOV2018,  11, 7,  20181111
    12NOV2018,  12, 1,  20181112
    13NOV2018,  13, 2,  20181113
    14NOV2018,  14, 3,  20181114
    15NOV2018,  15, 4,  20181115
    16NOV2018,  16, 5,  20181116
    17NOV2018,  17, 6,  20181117
    18NOV2018,  18, 7,  20181118
    19NOV2018,  19, 1,  20181119
    20NOV2018,  20, 2,  20181120
    21NOV2018,  21, 3,  20181121
    22NOV2018,  22, 4,  20181122
    23NOV2018,  23, 5,  20181123
    24NOV2018,  24, 6,  20181124
    25NOV2018,  25, 7,  20181125
    26NOV2018,  26, 1,  20181126
    27NOV2018,  27, 2,  20181127
    28NOV2018,  28, 3,  20181128
    29NOV2018,  29, 4,  20181129
    30NOV2018,  30, 5,  20181130
    ;

    /*COMMENT: I TAKE TODAY IN VARIABLE*/
    %LET EXTRACT_DATE_DT = date();

    /*COMMENT: I CREATE EMPTY TABLE TO STOCK OF PROCESS*/
    Proc sql;
    Create table GENERAL_STOCK as
    Select
    *
    FROM WORK.CONTROL_FILES_BASE
    WHERE ACTIVE = 2
    ;quit;

   /*START MAIN MACRO*/ 
    %macro GENERATE_STOCK();

    /*COMMENT: I check how many processes should be generated.*/
        PROC SQL noprint;
            Select
            count(*) into :i
            From work.CONTROL_FILES_BASE
            WHERE Nr_week_day <> '0'
        ;quit;
    %PUT &i;

    /*COMMENT: I separated process which should be check*/
    Proc sql;
    Create table STOCK_2 as
    Select
    monotonic() as ROW_ID,
    *
    FROM work.CONTROL_FILES_BASE
    WHERE Nr_week_day ne '0'
    ;quit;

    /*MAIN LOOP - I take field NR_WEEK_DAY and will check that this number of day is today - row by row*/
    %do ITER = 1 %To &i;

                Proc sql;
                Select
                    Nr_week_day into :SET_VAR
                    from STOCK_2
                    WHERE ROW_ID = &ITER
                ;quit;
            %PUT &SET_VAR;
    /*SET_VAR have value from Nr_week_day*/

        %LET l_decision = 0;/*I set default value in variable*/
    /*below code I found in forum - this macro reverse query - check whether (1,3,6) is included today - in table KALENDARIUSZ*/
            %macro nos_obs(dsn=,where_stmt=);
                proc sql;
                    select 
                    count(*) 
                    into :l_decision
                    from &dsn.
                    &where_stmt.
                ;quit;
            %mend ;
            %nos_obs(dsn=Kalendariusz,where_stmt=where Nr_week_day in &&SET_VAR. and Ref_date = &EXTRACT_DATE_DT.);
        %PUT &l_decision;

    /*IF ABOVE CODE RETURN 1 -  means that the nr_week_day is today */
        /*When l_decisions is 1 then process should add this row to general_stock. If 0 - should add nothing.*/
        %if &l_decision = 1 %then
            %do;
                Proc sql;
                Create table STOCK_2_INSERT (drop=ROW_ID) as
                Select
                *
                FROM WORK.STOCK_2
                WHERE ROW_ID = &ITER
                ;quit;

                Proc sql;
                    insert into GENERAL_STOCK
                    select * from work.STOCK_2_INSERT
                ;quit;

                /*I clear temp table*/
                Proc sql;
                    delete FROM WORK.STOCK_2_INSERT
                ;quit;
            %end;
        %else %if &l_decision = 0 %then
            %do;
            %end;
    %end;
    %mend GENERATE_STOCK;
    %GENERATE_STOCK();

/*AND I LOOK AT GENERAL TABLE*/
    Proc sql;
    Create table SHOW_GENERAL_STOCK as
    Select
    *
    FROM WORK.GENERAL_STOCK
    ;quit;

1 Ответ

0 голосов
/ 10 ноября 2018

Как объяснено в ответах на ваш другой вопрос , плохая идея определять макрос в другом определении макроса. В вашем примере это означает, что вы можете переместить определение макроса утилиты% nos_obs:

%macro nos_obs(dsn=,where_stmt=);
  proc sql;
    select 
    count(*) 
    into :l_decision
    from &dsn.
    &where_stmt.
    ;quit;
%mend ;

Этот блок кода не должен быть внутри блока:

%macro GENERATE_STOCK;
   ...
%mend GENERATE_STOCK;

Вы по-прежнему можете вызывать% nos_obs из% generate_stock. Только не вкладывайте определения макросов. В итоге вы получите:

*define a macro;
%macro nos_obs(dsn=,where_stmt=);
...
%mend ;

*define a macro that does some stuff and invokes another macro;
%macro GENERATE_STOCK;
   ...
   %nos_obs(dsn=...)
   ...
%mend GENERATE_STOCK;

%generatestock

В этом и заключается общий смысл отсутствия вложенных определений макросов. К вашей общей картине похоже, что вы пишете планировщик в SAS. Например, linux cron или windows scheduler, где вы решаете, какие программы запускать в зависимости от дня недели. Обычно лучше использовать специальное решение планировщика (cron, LSF, планировщик Windows и т. Д.), А не писать свое. Лучше означает проще, удобнее в обслуживании, более гибко и т. Д. Они позволят вам управлять зависимостями , пауза и перезапуск и т. д. и т. д.

Тем не менее, если вы пишете свой собственный планировщик в SAS (многим это удается, иногда трудно устоять перед искушением), я думаю, что код, который вы показали, намного сложнее, чем он должен быть.

У вас есть контрольный набор данных, в котором перечислены дни, в которые должен выполняться каждый процесс:

data CONTROL_FILES_BASE;
   input  Priority : 2.
          ACTIVE: 1.
          PROCES_NAME: $10.
          Nr_week_day: $10.

;   cards;
1 1 TEST_01 (1,3,6)
2 1 TEST_02 0
3 1 TEST_03 (4,5)
;

Если вы хотите определить, какие процессы должны запускаться сегодня, вам просто нужно выяснить, какой сегодня день недели, и соответственно выбрать записи. Что-то вроде:

data General_Stock ;
  set CONTROL_FILES_BASE ;
  where findc(Nr_week_day,put(weekday(today()),1.)) ;
run ;

Когда я пишу это, это суббота, поэтому weekday (today ()) возвращает 7, и выше выбирается 0 записей, потому что нет процессов, запланированных для выполнения по субботам.

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

%macro GENERATE_STOCK
  (data=/*name of input control dataset*/
  ,out= /*name of output dataset*/
  ,ExtractDate=/*extract date is a SAS date or expression like today() */
  );

  data &out ;
    set &data ;
    where findc(Nr_week_day,put(weekday(&extractDate),1.)) ;
  run ;

  title1 "Printout of &out genenerated when ExtractDate=%superq(ExtractDate)" ;
    proc print data=&out ;
    run ;
  title1 ;

%mend GENERATE_STOCK ;

Тест как:

%generate_stock(data=control_files_base,out=wantToday    ,extractdate=today())
%generate_stock(data=control_files_base,out=wantSunday   ,extractdate="11Nov2018"d)
%generate_stock(data=control_files_base,out=wantMonday   ,extractdate="12Nov2018"d)
%generate_stock(data=control_files_base,out=wantTuesday  ,extractdate="13Nov2018"d)
%generate_stock(data=control_files_base,out=wantWednesday,extractdate="14Nov2018"d)
%generate_stock(data=control_files_base,out=wantThursday ,extractdate="15Nov2018"d)
%generate_stock(data=control_files_base,out=wantFriday   ,extractdate="16Nov2018"d)
%generate_stock(data=control_files_base,out=wantSaturday ,extractdate="17Nov2018"d)
...