Search code examples
parametersmacrossascallexecute

Passing an equals sign to a macro in SAS


I'm trying to generate code in a data step, and then pass the code into a macro which then runs the code. It's a bit roundabout, I know, but I can't think of a better solution, since the contents of my code are based on what's in the dataset.

In my dataset, "test2", I have only one observation of the variable "statement", which is equal to

j1=input(j,anydtdtm.); drop j; rename j1=j; k1=input(k,anydtdtm.); drop k; rename k1=k; l1=input(l,anydtdtm.); drop l; rename l1=l;

I have a macro which is basically

%macro dummy(ds,statements);
    data &ds.2;
        set &ds.;    
        &statements.
    run;
%mend;

then I use call execute to the following:

data test3;
    set test2;
    call execute('%dummy('||strip(ds)||','||strip(statement)||')');
run;

But I get the following error:

ERROR: The keyword parameter J1 was not defined with the macro.

Clearly SAS is interpreting my "=" sign as something other than the contents of a macro variable. I tried using %str and altering my call execute to:

data test3;
    set test2;
    call execute('%dummy('||strip(ds)||','||%str(strip(statement))||')');
run;

but it didn't work. Anyone have any ideas?

Thanks for your help!!


Solution

  • First off, if you use named parameters, this isn't a problem.

    %macro dummy(ds=,statements=);
        data &ds.2;
            set &ds.;    
            &statements.
        run;
    %mend;
    
    
    data class;
      set sashelp.class;
    run;
    
    data fixes;
      infile datalines truncover;
      length statement $40 all_statements $512 execstr $1024;
      do _n_ = 1 to 2;
          input @1 statement $40.;
          all_statements=catx(';',all_statements,statement);
      end;
      put all_statements;
      execstr = cats('%dummy(ds=class,statements=',all_statements,';)');
      call execute(execstr);
      datalines;
    if sex='M' then m_height=height
    if sex='F' then f_height=height
    ;;;;
    run;
    

    Then SAS sees the named-parameter equal sign and knows that everything from that to the next comma is the value of that parameter.

    Of course, if you have a comma, you still need to do something. Here is where you were close-but-not-quite. %str needs to be quoting the macro call, not the construction of the macro call - in other words, it needs to be inside the quotes.

    data fixes;
      infile datalines truncover;
      length statement $40 all_statements $512 execstr $1024;
      do _n_ = 1 to 2;
          input @1 statement $40.;
          all_statements=catx(';',all_statements,statement);
      end;
      put all_statements;
      execstr = cats('%dummy(ds=class,statements=%nrstr(',all_statements,';))');
      call execute(execstr);
      datalines;
    if sex in ('M','F') then mfheight=height
    if sex='F' then f_height=height
    ;;;;
    run;
    

    Personally I like %nrstr here since it also eliminates those pesky ampersands and percent signs, which might have some meaning.

    Putting it there means that when SAS runs that call execute, it passes along that %str or %nrstr and quotes the value that is being sent on.

    When you had it in the other place:

    execstr = cats('%dummy(ds=class,statements=',%nrstr(all_statements),';)');
    

    What was being protected/quoted was not the text inside all_statements but actually the characters all_statements (in other words, the variable name). That doesn't really do much for you.