我有一个非常大的宏,我想多次打电话。 (我使用重复权重来计算我的错误。)我想调用不同变量的过程,比如VAR1-VAR99。在过去,我使用了DATA NULL 步骤和CALL EXECUTE,如下所示:
data _null_;
do i=1 to 99;
call execute(compress("%mymacro(VAR" || i || ")") );
end;
run;
但这次对我来说并不适合。关于宏变量的范围,我可能会遗漏一些东西?我想致电:
%mymacro(VAR1)
%mymacro(VAR2)
...
%mymacro(VAR99)
当然我想在没有99行代码的情况下这样做。为什么我的方法突然失败了?有什么其他方法可以做到这一点?
答案 0 :(得分:2)
以下是使用call execute生成宏调用的示例。我添加了%NRSTR,因为它可以防止宏时序问题。它使调用execute生成宏调用,而不实际执行宏。如果您的宏从数据生成宏变量,而没有%NRSTR,您可能会遇到时间问题和范围问题。
%macro mymacro(var) ;
%put var=&var ;
%mend mymacro ;
data _null_;
do i=1 to 5;
call execute(cats('%nrstr(%mymacro(var',i,"))")) ;
end;
run;
或者它可能就像更改代码以使用单引号而不是双引号一样简单。单引号将阻止宏在数据步骤编译时执行。如果您的宏不从数据生成宏变量,这可能就足够了。但我总是使用%NRSTR。
data _null_;
do i=1 to 5;
call execute(compress('%mymacro(VAR' || i || ")") );
end;
run;
答案 1 :(得分:1)
不要使用call execute,尝试在宏程序中调用宏程序。
%macro repeat(n);
%do i=1 %to &n;
%mymacro(VAR&i);
%end;
%mend;
答案 2 :(得分:0)
大可能是该问题中的关键词。让我解释一下。
您正在使用call execute()
将宏调用推送到堆栈。但实际上放在堆栈上的是由宏而不是调用生成的代码。查看SAS日志开头的+
行。
如果宏只生成几行代码,那么在数据步骤之后运行的内容就不多了。但如果它是大那么你可能会重叠堆栈。
此外,如果宏使用它生成的SAS代码行来创建宏变量(使用call symputx()
或SQL的into
子句),稍后驱动宏的逻辑就会出现时序问题。对于大宏而言,与小(简单)宏相比,更有可能发生这种情况。
在%nrstr()
中包裹宏呼叫(或至少是宏名称)将阻止SAS在call exucute()
呼叫期间运行宏。相反,宏调用将放在堆栈上,以便在数据步骤完成后运行。
考虑这个简单的宏定义。
%macro mymacro(varname);
proc means data=sashelp.class ;
var &varname ;
run;
%mend mymacro;
如果我使用call execute()
生成对它的调用:
data _null_;
call execute('%mymacro(age)');
call execute('%mymacro(height)');
call execute('%mymacro(weight)');
run;
然后你会在SAS日志中看到这样的行
1 + proc means data=sashelp.class ; var age ; run;
2 + proc means data=sashelp.class ; var height ; run;
3 + proc means data=sashelp.class ; var weight ; run;
但是如果你改为添加%nrstr()
:
data _null_;
call execute('%nrstr(%mymacro)(age)');
call execute('%nrstr(%mymacro)(height)');
call execute('%nrstr(%mymacro)(weight)');
run;
然后SAS日志中的行看起来像这样。
1 + %mymacro(age)
2 + %mymacro(height)
3 + %mymacro(weight)