如何在更新宏变量的数据步骤中调用宏并立即使用该值?
How to call a macro in a data step that updates a macro variable and use that value immediately?
下面的例子非常简单,可以用更简单的方法解决。但是,我有兴趣让它发挥作用。以下示例基于 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;
现在我想调用宏但只是为了更新 obs(从输入语句)。我使用:
data work.test;
set mycontents;
if name ne "Type" then do;
call execute('%nrstr(%fun('||name||');');
new = &obs;
end;
else new = 5;
运行;
简而言之,这应该迭代 mycontents 的行。然后根据名称调用一个(多个)宏,这会更新 obs。然后我可以简单地用 obs 填充新列 new。但是,obs 对所有名称保持相同的值,即最后一个变量的值。
这里的问题是双重的。
首先,您不能在此上下文中使用 CALL EXECUTE
,因为它直到 数据步骤完成 运行 后才会执行:所以任何取决于在 &obs
上将无法获得更新的值。你必须使用 dosubl
.
其次,如果要获得更新值 mid-data 步骤,则需要使用 symget('obs')
,而不是 &obs
。 &obs
会在编译数据步骤时解析,因此在执行过程中无法更改;但是 symget(obs)
指示数据步骤在执行期间查询符号 table。
这是一个使用 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;
下面的例子非常简单,可以用更简单的方法解决。但是,我有兴趣让它发挥作用。以下示例基于 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;
现在我想调用宏但只是为了更新 obs(从输入语句)。我使用:
data work.test;
set mycontents;
if name ne "Type" then do;
call execute('%nrstr(%fun('||name||');');
new = &obs;
end;
else new = 5;
运行;
简而言之,这应该迭代 mycontents 的行。然后根据名称调用一个(多个)宏,这会更新 obs。然后我可以简单地用 obs 填充新列 new。但是,obs 对所有名称保持相同的值,即最后一个变量的值。
这里的问题是双重的。
首先,您不能在此上下文中使用 CALL EXECUTE
,因为它直到 数据步骤完成 运行 后才会执行:所以任何取决于在 &obs
上将无法获得更新的值。你必须使用 dosubl
.
其次,如果要获得更新值 mid-data 步骤,则需要使用 symget('obs')
,而不是 &obs
。 &obs
会在编译数据步骤时解析,因此在执行过程中无法更改;但是 symget(obs)
指示数据步骤在执行期间查询符号 table。
这是一个使用 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;