我有一个大型数据集,我在那里存储宏参数。宏本身用于调用许多其他宏,每个宏都运行许多操作。
理想情况下,我想使用另一个宏来遍历数据集的每一行,构造(使用:CALL
)宏调用,将其存储在宏变量PUT &CALL.;
中,然后调用在循环的每次迭代中使用变量(使用 %macro OUTER_LOOP(DS);
%let K = ;
%COUNT_ROWS(DS, K); /* This stores the number of rows in DS in K. */
%do i = 1 %to &K.;
proc sql noprint; ...; quit; /* Create the macro call, and store it in :CALL. */
%put &CALL.;
%end;
%mend;
%OUTER_LOOP;
)即:
CALL EXECUTE();
这不能按预期工作:我的宏中存在的一些内部检查表明缺少由宏创建的几个数据集。奇怪的是,当我不在宏循环中运行它时(即我手动创建宏调用,逐行并执行它),不会发生错误。
有没有人遇到过这个问题?如果是这样,是否有人熟悉仍然允许我循环宏调用的解决方案?我知道class I(object): pass
class A(I): pass
class B(I): pass
my_parents = [A, B]
class C(*my_parents): pass
(在数据步骤中)在不同的时间运行宏的不同部分 - 在这种情况下发生了什么?
答案 0 :(得分:0)
我会在DO循环中添加%put Loop iterating: i=&i k=&k ;
。这将让你看到循环迭代的次数。一种可能性是循环比你想要的更早退出。如果是这种情况,原因可能是您在%Outer_Loop中用于循环的宏变量i
与您在其中一个内部宏中使用的另一个宏变量i
之间的冲突。作为一般规则,将宏变量定义为它们所定义的宏的%LOCAL
是个好主意。这样做可以防止这种宏变量冲突。但是没有看到内在的宏,那只是一种可能性。
您还可以在do循环中添加%put %superq(Call) ;
。这将显示正在生成的宏调用,因此您可以检查是否在每次调用中获得了预期的参数值。
答案 1 :(得分:0)
最有可能是一个范围问题。您的子宏可能会覆盖调用宏中宏变量的值。
您可以使用%local
语句将所有变量声明为局部变量来解决此问题。如果在宏运行后需要访问宏变量,请将它们显式声明为%global
。
因此,对于上面列出的宏,您需要以下行:
%local k i;
不要忘记你需要为任何被调用的子宏执行此操作,等等......
答案 2 :(得分:0)
通过自己生成代码,可以避免很多这类问题。对于您的示例,您可以将生成代码的逻辑从SQL移动到数据步骤,然后将宏只需要数据步骤而不是宏。您甚至不需要提前知道数据集中的观察数量。
filename code temp ;
data _null_;
set DS ;
file code ;
put '.... generated code based on values in current data ... ;
run;
%include code / source2 ;