【问题标题】:SAS Macro Do Loop not resolvingSAS 宏循环不解决
【发布时间】:2013-08-08 10:26:17
【问题描述】:

谁能告诉我为什么这不能解决:

/*put all transaction table names into a data set*/ 
/*(table names are of format transac_20130603_20130610 (date from and date to)*/
data transaction_tables;
    set SASHELP.VTABLE (keep=libname memname);
    where lowcase(substr(memname,1,8))='transac_'

run;
/*sort and add rownumbers*/
proc sql;
create table transaction_tables as
    select *, monotonic() as rownum
         from transaction_tables
             order by memname;
run;
/*find rownumber of first and last transaction tables with run dates before campaign start and after end date of campaign*/
data _NULL_;
set transaction_tables;
    if substr(memname,9,8)<=&pre_period_start. and substr(memname,18,8)>=&pre_period_start. then do;
        call symput("r1", rownum);
        stop; 
        end;
run;        
data _NULL_;
set transaction_tables;
    if substr(memname,9,8)<=&max_enddate. and substr(memname,18,8)>=&max_enddate. then do;
        call symput("r2", rownum);
        stop;
        end;
run;
%put &r1; %put &r2;
/*r1 = 11, r2 = 27 - both resolving OK*/

/*get all relevant transaction table names where rownumbers are between r1 and r2*/
/*r1=11 and r2=27 so my transaction table name macros should run from t_0 to t_16/*
%macro trans;
%let y = %eval(&r2 - &r1);
%do i=0 %to &y;
data _NULL_;
set transaction_tables;
    if rownum = &r2 - (&r2 - &r1 - &i)  then do;
        call symput("t_&i", cats(libname, '.', memname));
        stop; 
        end;
%end;
%mend trans;
%trans;

%put &t_0;
--WARNING: Macro variable "&t_0" was not resolved

我不完全确定为什么,但由于弄乱了一些变量,我认为问题在于它试图将表名分配给 t_&i 宏的最后一部分。我认为问题在于在尝试调用另一个宏变量时尝试命名宏变量(尝试在 i=0 时通过调用 &i 来创建宏 t_0)。我想我在语法上搞砸了,因为我认为逻辑相当合理。

谢谢!

【问题讨论】:

  • 解决宏问题的一个好方法是让代码在没有宏的情况下执行。你所做的只是代码替换......要让代码执行很长的路要走,开始一次一点地放入宏代码。

标签: loops macros sas sas-macro do-loops


【解决方案1】:

在不判断您正在尝试做的事情的有用性的情况下:

这是一个范围问题。您在宏中创建的任何宏变量仅存在于该宏中。 如果您希望它存在于您的宏之外,您需要:

  • 在打开代码(而不是在宏中)和执行宏之前创建宏变量。
  • 在您的宏中将其显式设置为全局(在第一次提及之前),您可以通过以下方式执行此操作:

    %global t_0;

编辑 另请注意,要结束 proc sql,您需要使用 quit 而不是 run。

【讨论】:

  • 另外,你能想出比我更有用的方法吗?我意识到使用 rownumbers 有点小题大做,我宁愿扫描每个表名以尝试找到正确的日期范围,而不是排序和使用 rownumbers。谢谢!
【解决方案2】:

替代方法:

proc sql;                                                                                                                               
create table result as                                                                                                                  
    select cats(libname,'.',memname) as desired                                                                                                      
    from dictionary.tables                                                                                                                  
    where substr(libname,1,8)='TRANSAC_'     
    and (scan(libname,2,'_')<=&pre_period_start. and scan(libname,3,'_')>=&pre_period_start.) 
    and (scan(libname,2,'_')<=&max_enddate. and scan(libname,3,'_')>=&max_enddate.) ;

data _null_;
    set result;
    call symput(cats('R_',_n_),desired,'g');
run;

甚至可以使用 SQL 'into' 子句将其重写为一个步骤。 SQL quit; 语句是可选的,我个人从不使用它。

【讨论】:

  • 刚刚注意到这与以下内容非常相似:stackoverflow.com/questions/18015218/…
  • 哈哈,是的,它非常相似,实际上我一周前问过这个问题,但该解决方案不涉及任何 do 循环宏,所以我没有现在遇到的 %global 问题。话虽如此,你这样做的方式看起来比我的简单很多,所以我可能会停止尝试聪明地使用 do 循环,而只是使用你上面写的内容。谢谢!!
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多