Search code examples
macrossasdo-loops

%DO Loop showing me error is SAS


i am wanted to create following data-sets, P1_31,P1_32,P1_36,P1_37 in SAS using following code

%MACRO P_MISS1;
%LET T1= 3 ;
%LET H1=1;
%DO %WHILE(&H1<=1);
        %LET TR1=%SCAN(&T1,&H1);
            %DO I= 1,2,6 %TO 7;
                DATA P1_&TR1&I;
                    VALUE=.;
                    COL&TR1=.;
                RUN;
                OUTPUT;
            %END;
     %LET H1=%EVAL(&H1+1);
 %END;
%MEND P_MISS1;

%P_MISS1

i used many macro program to all those above data-sets, but just to reduce the code size i was creating the following code. i know i am doing something wrong with %Do Loop. Please guide me with the code, if there is any possibility to use above code.


Solution

  • The better way to write this sort of code, just like any programming language, is to write the macro as the piece you want to run multiple times, and then call it multiple times. That makes it more reusable, makes more clear what you're doing, and ultimately ends up with shorter code much of the time.

    This particular set of code it's not entirely obvious how the best way to write it would be, because the things driving your inputs aren't obvious. However, something like this would make sense.

    %macro make_ds(tr,i);
    DATA P1_&TR1&I;
      VALUE=.;
      COL&TR1=.;
    RUN;
    %mend make_ds;
    
    %macro call_make_ds(tr);
      %make_ds(&tr,1);
      %make_ds(&tr,2);
      %make_ds(&tr,6);
      %make_ds(&tr,7);
    %mend call_make_ds;
    

    For four items I'd just write them out, if there's no dataset or other entity that contains the four items. It's just as much code frankly to write the complex loop, more error prone, and not really much easier to maintain. If you have a dataset that contains the possible values for i, then use that to call the %make_ds macro.

    Then call that macro based on the appropriate parameters. For example, if TR can be determined from a dataset (say you have a dataset that contains all TR values you want to iterate over), you could do something like this:

    proc sql;
    select distinct cats('%call_make_ds(',trval,')') into :makelist 
     separated by ' ' 
     from your_ds;
    quit;
    &makelist;