Search code examples
sassas-macro

How can I use %SCAN within a macro variable name?


I'm trying to write robust code to assign values to macro variables. I want the names of the macro variables to depend on values coming from the variable 'subgroup'. So subgroup could equal 1, 2, or 45 etc. and thus have macro variable names trta_1, trta_2, trt_45 etc.

Where I am having difficulty is calling the macro variable name. So instead of calling e.g. &trta_1 I want to call &trta_%SCAN(&subgroups, &k), which resolves to trta_1 on the first iteration. I've used a %SCAN function in the macro variable name, which is throwing up a warning 'WARNING: Apparent symbolic reference TRTA_ not resolved.'. However, the macro variables have been created with values assigned.

How can I resolve the warning? Is there a function I could run with the %SCAN function to get this to work?

data data1 ;
  input subgroup trta trtb ;
  datalines ;
  1 30 58
  2 120 450
  3 670 3
run;

%LET subgroups = 1 2 3 ;
%PUT &subgroups;

%MACRO test;
  %DO k=1 %TO 3;

    DATA test_&k;
      SET data1; 
      WHERE subgroup = %SCAN(&subgroups, &k);
      CALL SYMPUTX("TRTA_%SCAN(&subgroups, &k)", trta, 'G');
      CALL SYMPUTX("TRTB_%SCAN(&subgroups, &k)", trtb, 'G'); 
    RUN;  

    %PUT "&TRTA_%SCAN(&subgroups, &k)" "&TRTB_%SCAN(&subgroups, &k)"; 
  %END;

%MEND test;
%test;

Solution

  • Using the structure you've provided the following will achieve the result you're looking for.

    data data1;
      input subgroup trta trtb;
      datalines;
    1 30 58
    2 120 450
    3 670 3
    ;
    run;
    
    %LET SUBGROUPS = 1 2 3;
    %PUT &SUBGROUPS;
    
    %MACRO TEST;
      %DO K=1 %TO 3;
    
        %LET X = %SCAN(&SUBGROUPS, &K) ;
    
        data test_&k;
          set data1; 
          where subgroup = &X ;
          call symputx(cats("TRTA_",&X), trta, 'g');
          call symputx(cats("TRTB_",&X), trtb, 'g'); 
        run;  
    
        %PUT "&&TRTA_&X" "&&TRTB_&X"; 
      %END;
    %MEND TEST;
    %TEST;
    

    However, I'm not sure this approach is particularly robust. If your list of subgroups changes you'd need to change the 'K' loop manually, you can determine the upper bound of the loop by dynamically counting the 'elements' in your subgroup list.

    If you want to call the macro variables you've created later in your code, you could a similar method.

    data data2;
      input subgroup value;
      datalines;
    1  20
    2  25
    3  15
    45 30
      ;
    run ;
    
    
    %MACRO TEST2;
      %DO K=1 %TO 3;
    
        %LET X = %SCAN(&SUBGROUPS, &K) ;
    
        data data2 ;
          set data2 ;
          if subgroup = &X then percent = value/&&TRTB_&X  ;
          format percent percent9.2 ;      
        run ;
      %END;
    %MEND TEST2;
    
    %TEST2 ;
    

    Effectively, you're re-writing data2 on each iteration of the loop.