我在数据步骤中调用一个宏,并将宏变量分配给数据步骤变量,如下所示。
宏的输入来自输入数据集,该输入数据集有大约500条记录。
%macro test(inp_var);
%global macro_var;
--- using inp_var variable here---
%if --some condition-- %then call symput('macro_var',-- some value--);
%mend;
data output;
set input;
%test(inp_var);
new_data_step_var = symget('macro_var');
run;
但它显示的错误信息指向变量 new_data_step_var - 错误180-322:语句无效或使用的顺序不正确。
答案 0 :(得分:4)
没有SAS宏实际上在数据步骤“内部”执行。宏语言处理器和数据步骤编译器作为共享代码输入流的两个不同子系统。当他们“吃掉”大块的SAS代码时,他们互相交换。在原始程序的情况下,SAS中的语言处理器会看到“数据”语句并切换到数据步骤编译器。检测到嵌入式%test宏调用,并将代码输入流交给宏处理器FIRST!宏处理器扩展了%test宏中的所有代码和宏逻辑,然后将整个代码流交还给SAS数据步骤编译器进行编译。
因此,在数据步骤编译之前,%test将运行完成。
如果您想在数据步骤中创建自己的子程序,请尝试proc fcmp。否则,只需按照建议在数据步骤中实现条件逻辑。
答案 1 :(得分:2)
使用datastep if / then重写它,而不是宏if if / then,并且不创建宏变量,只需使用datastep变量。
%MACRO TEST(var) ; call missing(tempvar) ; if --some condition-- then tempvar = --some value-- ; %MEND ; data output ; set input ; %TEST(inp_var) ; new_var = tempvar ; drop tempvar ; run ;
答案 2 :(得分:1)
您不能在使用call symput设置的相同数据步骤中使用宏变量。 您的呼叫同意声明的结果仅在数据步骤之后可用。
因此,在处理symget语句时,宏变量尚不存在。 此外,它似乎毫无意义,为什么不使用retain语句来保存您想要的值?
e.g:
data output;
set input;
retain new_data_step_var;
if --some condition -- then new_data_step_var = --some value--;
run;
答案 3 :(得分:1)
包含proc或数据步骤的宏不能在数据步骤中执行。宏不是函数或子程序;它们是文本,就像你输入它一样(只是节省一些循环和条件的时间)。因此,宏的内容需要是可以在数据步骤中执行的文本:
%macro mymacro(numiters);
*this macro would be easier to do in an array, but it is an example;
%local t;
%do t = 1 to &numiters.;
x&t. = mean(y&t.,z&t.);
%end;
%mend mymacro;
data output;
set input;
%mymacro(5);
run;
在这种情况下,不将值存储在宏变量中更容易(并且在风格上更正确)。只需将结果包含在数据步变量中,如果需要,将该变量的名称作为参数之一传递。
还有函数式宏,它实际上将值返回到数据步骤(或者在这种情况下,返回等于值的文本)。它们可以在等号的右侧使用。
%macro xtothey(in,power);
%local t;
&in.
%do t = 1 to &power-1;
*&in.
%end;
;
%mend myfunctionmacro;
data output;
set input;
y = %xtothey(x,4);
run;
这实际上在PROC FCMP(编译函数和子程序)中更容易完成,但有时候宏更好(或者你可能不太了解FCMP)。
最后,一些宏需要自己的proc或数据步骤。在这些情况下,除非您使用某些FCMP元素(如DOSUBL),否则您需要将值存储在某处,无论是在数据集还是宏中。在这些情况下,您必须在datastep之前运行您想要值的宏 - 但是您只获得一个(或有限数量的)返回值。除非你采用一些极端的长度,否则每行不会得到一个,这通常可以在不使用宏变量的情况下更好地完成。我认为下面是不好的形式,因为你几乎总是可以在不使用宏变量的情况下做得更好 - 但如果你需要,你可以这样做。带有DOSUBL的FCMP可能是最好的选择。
%macro findmode(dset,var,outvar);
proc means data=&dset;
var &var.;
output out=_tempset mode(&var.)=&var._mode;
run;
data _null_;
set _tempset;
call symputx("&outvar.",&var._mode);
run;
%mend findmode;
%findmode(sashelp.class,weight,wtmode);
data output;
set input;
mode=&wtmode;
run;