How to call a macro in a data step that updates a

2019-07-15 05:37发布

问题:

The following example is very simple and might be solvable in an easier way. However, I am interested in making it work. The following example is based on the cars-dataset of the sashelp-library. First, I have a macro called fun:

proc contents data = sashelp.cars out = mycontents;
run;

%macro fun(var);
proc sql noprint;
        select count(distinct(&var.))
        into :obs
        from sashelp.cars;
quit;
%mend;

Now I want to call the macro but only to update obs (from the input statement). I use:

data work.test;
set mycontents;
if name ne "Type" then do;
      call execute('%nrstr(%fun('||name||');');
      new = &obs;
end;
else new = 5;

run;

In short, this should iterate the rows of the mycontents. Then call one (of several) macros depending on name, which updates obs. Then I can simply populate the new column new with obs. However, obs stays the same value for all names, which is the value from the last variable.

回答1:

Here the problem is twofold.

First, you cannot use CALL EXECUTE in this context because that doesn't execute until after the data step has completed running: so anything depending on &obs will not be able to get an updated value for that. You'll have to use dosubl.

Second, you need to use symget('obs'), not &obs, if you want to get an updated value mid-data step. &obs will resolve when the data step is compiled, so it cannot change during execution; but symget(obs) instructs the data step to query the symbol table during execution.

Here's an example of doing this with dosubl, minimally changed from your example. Note the %global statement to make sure obs is available to us in the data step (there are other ways to do this to get it back that are better - namely, wrapping this in a fcmp function and using run_macro - but this is closest to how you do it).

proc contents data = sashelp.cars out = mycontents;
run;

%macro fun(var);
%global obs;
proc sql noprint;
        select count(distinct(&var.))
        into :obs
        from sashelp.cars;
quit;
%mend;

data work.test;
set mycontents;
if name ne "Type" then do;
      rc = dosubl(cats('%fun(',name,')'));
      new = symgetn('obs');
end;
else new = 5;
run;


标签: sas sas-macro