以下示例非常简单,可以更容易地解决.但是,我有兴趣让它发挥作用.以下示例基于sashelp-library的cars-dataset.首先,我有一个名为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;
Run Code Online (Sandbox Code Playgroud)
现在我想调用宏但只是更新obs(来自输入语句).我用:
data work.test;
set mycontents;
if name ne "Type" then do;
call execute('%nrstr(%fun('||name||');');
new = &obs;
end;
else new = 5;
Run Code Online (Sandbox Code Playgroud)
跑;
简而言之,这应该迭代mycontents的行.然后根据名称调用一个(多个)宏,更新obs.然后我可以简单地用obs填充新列new.但是,obs对所有名称保持相同的值,这是最后一个变量的值.
这里的问题是双重的.
首先,您不能CALL EXECUTE在此上下文中使用,因为直到数据步骤完成运行后才会执行:因此任何依赖于此的内容&obs都无法获取更新的值.你必须使用dosubl.
其次,你需要使用symget('obs'),不&obs,如果你想获得一个更新的值中间数据的一步. &obs将在编译数据步骤时解决,因此在执行期间不能更改; 但symget(obs)指示数据步骤在执行期间查询符号表.
这是一个这样做的例子,与dosubl你的例子相比变化很小.请注意%global确保obs在数据步骤中可以使用的语句(还有其他方法可以将它更好地恢复 - 即将它包装在一个fcmp函数中并使用run_macro- 但这最接近你的工作方式) .
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;
Run Code Online (Sandbox Code Playgroud)