如何在更新宏变量并立即使用该值的数据步骤中调用宏?

Pat*_*ada 2 sas sas-macro

以下示例非常简单,可以更容易地解决.但是,我有兴趣让它发挥作用.以下示例基于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对所有名称保持相同的值,这是最后一个变量的值.

Joe*_*Joe 6

这里的问题是双重的.

首先,您不能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)