SAS中调用execute-macro脚本中的动态变量

时间:2017-11-08 08:58:11

标签: loops macros sas

我有一个宏,它将生成一个包含列prod和另外12列的数据集。我还有一个表prodincl_fr,其中包含下面的示例数据集。

Rownum prodcat
----------
1      L
2      L1
3      M
4      LM
...    ...

我想做一个do until循环,它将调用宏%runlimitsquery并在每次迭代中使用prodcat的值。

我无法弄清楚如何在SAS中编写这个代码。我正在玩下面的代码。注意reccount = prodincl_fr的行数。

data _null_;
set prodincl_fr;
do until(rownum=reccount);
  prod=prodcat;
  call execute('%nrstr(%runlimitsquery(&prod))');
  output;
end;
run;
希望你能帮助我。请!

2 个答案:

答案 0 :(得分:1)

如果已知的codegen数量少于64K字符,则可以使用SQL来准备宏调用。我觉得这种代码风格对读者来说特别清楚。

%macro runlimitsquery(prodcat);
  %put &sysmacroname called with &=prodcat;
%mend;

data prodcats;
  input prodcat $ @@;
datalines;
auto boat home flood aux worker life
run;

proc sql noprint;
  select 
    cats('%runlimitsquery(',prodcat,')')
  into
    :invoker separated by ' '
  from
    prodcats
  ;
quit;

%put NOTE: invoker=%superq(invoker); * lets see what is going to be invoked (the codegen);

* invoke the codegen;
&invoker

日志的最后部分

134  %put NOTE: invoker=%superq(invoker); * lets see what is going to be invoked (the codegen);
NOTE: invoker=%runlimitsquery(auto) %runlimitsquery(boat) %runlimitsquery(home)
%runlimitsquery(flood) %runlimitsquery(aux) %runlimitsquery(worker) %runlimitsquery(life)
135
136  * invoke the codegen;
137  &invoker
RUNLIMITSQUERY called with PRODCAT=auto
RUNLIMITSQUERY called with PRODCAT=boat
RUNLIMITSQUERY called with PRODCAT=home
RUNLIMITSQUERY called with PRODCAT=flood
RUNLIMITSQUERY called with PRODCAT=aux
RUNLIMITSQUERY called with PRODCAT=worker
RUNLIMITSQUERY called with PRODCAT=life

如果codegen将超过64k字符,您可能想退后一步,重新考虑手头任务的内容和方式。

答案 1 :(得分:0)

您的代码存在一些问题。

  • reccount不是prodincl_fr数据集的变量,因此不存在于该datastep的上下文中。因此do语句等同于do until(rownum=.)
  • 您正在为数据集中的每条记录调用该循环。因此,在该循环的整个迭代中,rownum的值将永远不会改变并且将保持当前观察中的rownum值。您的until条件永远不会得到满足,您的代码将永远运行。
  • &prod是对宏变量的引用。但是当您在prod=prodcat步骤中编写data时,您将创建一个数据步变量,而不是宏变量。因此&prod不存在。
  • 即使如果 prod宏变量存在,也无法解析,因为对它的引用用单引号括起来。 SAS不会尝试在单引号字符串中解析宏代码/引用。你需要使用双引号。

该代码将语法正确,如下所示:

data _null_;
set prodincl_fr nobs=reccount;
do i=1 to reccount;
  prod=prodcat;
  call execute('%runlimitsquery('||prod||');');
  output;
end;
run;

HOWEVER ,如果,让我们说prodincl_fr包含一千条记录,那会怎么做:你的datastep会转到{{1}的第一条记录}},启动循环,该循环将使用prodincl_fr的相同值调用您的宏一千次,这将是当前记录的prod的值;然后它会移动到第二个记录并用该记录的prodcat值再调用一千次;等等,直到千分之一记录。

因为我认为这不是你想要的,并且因为带有prodcat语句的数据步骤隐式迭代所有记录,你可以取消do循环并像这样编写你的datastep: / p>

set
相关问题