问题
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;
来源:https://stackoverflow.com/questions/42031936/how-to-call-a-macro-in-a-data-step-that-updates-a-macro-variable-and-use-that-va