多次调用一个宏

时间:2018-06-14 21:03:16

标签: sas

我有一个非常大的宏,我想多次打电话。 (我使用重复权重来计算我的错误。)我想调用不同变量的过程,比如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行代码的情况下这样做。为什么我的方法突然失败了?有什么其他方法可以做到这一点?

3 个答案:

答案 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)