如何在更新宏变量的数据步骤中调用宏并立即使用该值? [英] How to call a macro in a data step that updates a macro variable and use that value immediately?
问题描述
下面的例子非常简单,可以用更简单的方法解决.但是,我有兴趣让它发挥作用.以下示例基于 sashelp-library 的 cars-dataset.首先,我有一个宏叫做 fun:
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;
现在我想调用宏,但只是为了更新 obs(来自输入语句).我用:
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;
运行;
简而言之,这应该迭代 mycontents 的行.然后根据名称调用一个(几个)宏,它会更新 obs.然后我可以简单地用 obs 填充新列.但是,对于所有名称,obs 保持相同的值,即最后一个变量的值.
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.
推荐答案
这里的问题是双重的.
首先,您不能在此上下文中使用 CALL EXECUTE
,因为直到 数据步骤完成运行后才会执行:所以任何取决于 &obs
将无法获得更新的值.您必须使用 dosubl
一个>.
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
.
其次,如果要获取更新的值中间数据步骤,则需要使用 symget('obs')
,而不是 &obs
.&obs
将在编译数据步骤时解析,因此在执行过程中无法更改;但是 symget(obs)
指示数据步在执行过程中查询符号表.
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.
这是一个使用 dosubl
执行此操作的示例,与您的示例略有不同.请注意 %global
语句以确保 obs
在数据步骤中可供我们使用(还有其他更好的方法可以将其取回 - 即包装这在 fcmp
函数中并使用 run_macro
- 但这是最接近你的做法).
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;
这篇关于如何在更新宏变量的数据步骤中调用宏并立即使用该值?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!