SAS:运行 do 循环内的宏似乎不起作用
SAS: Running macros inside do loop does not seem to work
我需要多次 运行 一系列宏。为此,我构建了一个新的宏,其中包含一个 do-loop,它应该 运行 "i" 次,并且随着 do-loop 的每次迭代,上面引用的一系列宏应该 运行。
这是代码的本质(请注意,第一个过程 sql 本质上取自名为 "DatesRange" 的数据集,并将日期范围放入变量 "varlist_Dates" 中;范围此变量中的日期用于 Macro1、Macro2、Macro3)。
%macro MultipleTimes;
proc sql noprint;
select distinct Date
into :varlist_Dates separated by ' '
from DatesRange
order by Date;
quit;
%do i = 1 %to 5;
%let date = %scan(&varlist_Dates.,&i.);
%Macro1;
%Macro2;
%Macro3;
%end;
%mend;
我发现它 在 i=1 处停止并且永远不会继续。我完全不清楚为什么。我尝试过删除一些宏并保留其他宏,但似乎没有任何效果。我觉得我的方法可能有一些更基本的东西是关闭的,因为我对 SAS 以及宏内部 do-loop 内部的宏工作方式不了解。
如有任何帮助,我们将不胜感激。谢谢!
首先:检查这些宏中是否使用了 i
。我敢打赌。它可能被更改为高于 5 的值(因此在一个循环后退出)。
在 SAS 中,当您引用 已经 存在的宏变量时,它被定义为具有包含它的最局部符号 table 的范围,除非您使用 %local
将其指定为当前宏的本地。因此,如果您在多个嵌套宏中使用 %let i=1 to 5;
,它将使用相同的 &i。
举个例子,看下面的代码:
%let i=A;
%macro outer;
%put &=i;
%do i=1 %to 5;
%put OUTER FIRST: &=i;
%inner;
%put OUTER LAST: &=i;
%end;
%mend outer;
%macro inner;
%do i=1 %to 5;
%put INNER: &=i.;
%end;
%mend;
%put GLOBAL FIRST: &=i;
%outer;
%put GLOBAL LAST:&=i;
请注意 &i
始终是相同的值。你不是这个意思吧?
现在,另一方面,如果你做得对,&i
确实会在每一位中获得不同的值:
%let i=A;
%macro outer;
%local i;
%put &=i;
%do i=1 %to 5;
%put OUTER FIRST: &=i;
%inner;
%put OUTER LAST: &=i;
%end;
%mend outer;
%macro inner;
%local i;
%do i=1 %to 5;
%put INNER: &=i.;
%end;
%mend;
%put GLOBAL FIRST: &=i;
%outer;
%put GLOBAL LAST:&=i;
如果您 %put _all_
在 INNER 中,您会看到它的实际效果。
第二:不要这样写。你会付出很多努力,只是把它写成一个更好的开始方式。
%Macro RunMyMacros(date=);
%Macro1; *I hope you use &date as a parameter in these and not as a global;
%Macro2;
%Macro3;
%mend RunMyMacros;
proc sql noprint;
select distinct cats('%RunMyMacros(date=',Date,')')
into :calllist_Dates separated by ' '
from DatesRange
order by Date;
quit;
&calllist;
这更易于使用、故障排除和 运行,并且不需要硬编码有效日期的数量或其中的任何其他内容。
我需要多次 运行 一系列宏。为此,我构建了一个新的宏,其中包含一个 do-loop,它应该 运行 "i" 次,并且随着 do-loop 的每次迭代,上面引用的一系列宏应该 运行。
这是代码的本质(请注意,第一个过程 sql 本质上取自名为 "DatesRange" 的数据集,并将日期范围放入变量 "varlist_Dates" 中;范围此变量中的日期用于 Macro1、Macro2、Macro3)。
%macro MultipleTimes;
proc sql noprint;
select distinct Date
into :varlist_Dates separated by ' '
from DatesRange
order by Date;
quit;
%do i = 1 %to 5;
%let date = %scan(&varlist_Dates.,&i.);
%Macro1;
%Macro2;
%Macro3;
%end;
%mend;
我发现它 在 i=1 处停止并且永远不会继续。我完全不清楚为什么。我尝试过删除一些宏并保留其他宏,但似乎没有任何效果。我觉得我的方法可能有一些更基本的东西是关闭的,因为我对 SAS 以及宏内部 do-loop 内部的宏工作方式不了解。
如有任何帮助,我们将不胜感激。谢谢!
首先:检查这些宏中是否使用了 i
。我敢打赌。它可能被更改为高于 5 的值(因此在一个循环后退出)。
在 SAS 中,当您引用 已经 存在的宏变量时,它被定义为具有包含它的最局部符号 table 的范围,除非您使用 %local
将其指定为当前宏的本地。因此,如果您在多个嵌套宏中使用 %let i=1 to 5;
,它将使用相同的 &i。
举个例子,看下面的代码:
%let i=A;
%macro outer;
%put &=i;
%do i=1 %to 5;
%put OUTER FIRST: &=i;
%inner;
%put OUTER LAST: &=i;
%end;
%mend outer;
%macro inner;
%do i=1 %to 5;
%put INNER: &=i.;
%end;
%mend;
%put GLOBAL FIRST: &=i;
%outer;
%put GLOBAL LAST:&=i;
请注意 &i
始终是相同的值。你不是这个意思吧?
现在,另一方面,如果你做得对,&i
确实会在每一位中获得不同的值:
%let i=A;
%macro outer;
%local i;
%put &=i;
%do i=1 %to 5;
%put OUTER FIRST: &=i;
%inner;
%put OUTER LAST: &=i;
%end;
%mend outer;
%macro inner;
%local i;
%do i=1 %to 5;
%put INNER: &=i.;
%end;
%mend;
%put GLOBAL FIRST: &=i;
%outer;
%put GLOBAL LAST:&=i;
如果您 %put _all_
在 INNER 中,您会看到它的实际效果。
第二:不要这样写。你会付出很多努力,只是把它写成一个更好的开始方式。
%Macro RunMyMacros(date=);
%Macro1; *I hope you use &date as a parameter in these and not as a global;
%Macro2;
%Macro3;
%mend RunMyMacros;
proc sql noprint;
select distinct cats('%RunMyMacros(date=',Date,')')
into :calllist_Dates separated by ' '
from DatesRange
order by Date;
quit;
&calllist;
这更易于使用、故障排除和 运行,并且不需要硬编码有效日期的数量或其中的任何其他内容。