2016-08-26 79 views
0

我正在尝试使用%DO循环追加多个每月数据文件。这里是我到目前为止的代码:SAS%DO循环检索多个数据集

options mprint symbolgen source mlogic merror syntaxcheck ; 


%MACRO INT; 

%DO i=01 %TO 03 %BY 1; 

libname appd "Qual1.Qual2.Qual3.QUAL416&i." disp=shr; 

data work&i.; 
set appd.file; 
run; 

data final; 
set work; 
run; 

proc append data=work&i. 
      base=final; 
run; 

%MEND; 

%INT; 

我得到一个错误:

警告:目前正在处理的引用字符串变得更加 超过262个字符。您可能有不平衡的报价 分数。

我从来没有收到过这个错误,我不完全确定它是什么意思。我试图创建这个宏来追加今年的几个文件,但理想情况下它会跨越多年。即改变mtro16 & i。到mtro & i。除了我不想明确地编码%DO i=1601 %TO 1612 %BY 1,因为我将不得不每年改变它,例如,如果我从2010年开始,我将不得不在2010年编码2010年,然后单独编制%DO 2011年的声明等,直到2016年。这听起来不是很多,但十年以上> +它可以。

更新:我改变了我的代码,以将此位:

`%DO i=1005 %TO 1607; 
%IF i=1013 %THEN %DO i=1101 %TO 1112; 
/*%ELSE %IF i=1113 %THEN %DO i=1201 %TO 1212;*/ 
/*%ELSE %IF i=1213 %THEN %DO i=1301 %TO 1312;*/ 
/*%ELSE %IF i=1313 %THEN %DO i=1401 %TO 1412;*/ 
/*%ELSE %IF i=1413 %THEN %DO i= 1501 %TO 1512;*/ 
/*%ELSE %IF i=1513 %THEN %DO i=1601 %TO 1607;*/` 

这是一种janky的,但我认为这是可行的,只循环到今年年底,然后i=1012 to i=1101后开始下一个迭代。然而,这是正在发生的事情在我的日志:

MLOGIC(INT): %DO loop index variable I is now 1012; loop will iterate again. 
MLOGIC(INT): %IF condition i=1013 is FALSE 
MLOGIC(INT): %DO loop index variable I is now 1013; loop will iterate again. 
MLOGIC(INT): %IF condition i=1013 is FALSE 

如何SAS治疗这种%IF条件?它告诉我变量i = 1013%IF条件i=1013是否为假?为什么这不是真的?

+0

我通常创建解析为一个字符串,字符串本身具有比指定的字符更宏观变量时收到这样的警告。它可以是完全有效的,并且工作正常,但SAS认为可能存在问题,因为它不是期望字符串的那么长。如果代码按预期行事,我不会担心,因为我认为你不能阻止它产生警告。也就是说,你没有%结束;关闭你的循环,所以它只是将它们连接在一起? –

+0

SMH。我一直都在想这些 – DukeLuke

+1

而且,do语句中的变量01在调用时会在宏中解析为1。所以你会通过mtro163结束mtro161。你需要添加一些东西,如果长度我<2然后做j = strip(0 || i)连接我怀疑的前导零,然后使你的libname mtro16&j。代替。 –

回答

2

我认为当使用日期时,您应该始终使用日期值,而不是通过使用年或月或其他此类“快捷方式”来尝试快捷方式。根据我的经验,这些总是会导致混淆或代码错误。

下面是一个宏,显示如何传递开始日期和结束日期(甚至不必是本月的第一天),它将返回相应的月度名称。然后,您可以根据需要调整它以与您的proc append或其他代码一起工作。

它实际上需要2 日期值作为参数。然后使用%do %while循环和intnx()函数一次从开始日期到结束日期循环1个月。我使用%sysfunc(sum(),yymmn4.)来计算每月数据集的所需格式并将其打印到日志中。

代码:

%macro append_monthly(iStart_date=, iEnd_date=); 

    %local tmp_date id; 
    %let tmp_date = %sysfunc(intnx(month,&iStart_date,0,beginning)) ; 

    %do %while (&tmp_date le &iEnd_date); 

    %let id = %sysfunc(sum(&tmp_date),yymmn4.); 
    %put &=id; 

    %let tmp_date = %sysfunc(intnx(month,&tmp_date,1,beginning)) ; 

    %end; 

%mend; 
%append_monthly(iStart_date=%sysfunc(mdy(1,1,2010)), iEnd_date=%sysfunc(mdy(1,1,2013))); 

注意,%sysfunc(sum(&tmp_date),yymmn4.)是一种使用宏时格式化数字的快捷方式。%sysfunc()要求我们提供一个函数作为第一个参数,并且您可以选择提供一个格式作为第二个参数。 sum()函数很方便,因为它使数值保持不变。

输出:

ID=1001 
ID=1002 
ID=1003 
... 
ID=1011 
ID=1012 
ID=1101 
ID=1102 
ID=1103 
... 
ID=1110 
ID=1111 
ID=1112 
ID=1201 
ID=1202 
ID=1203 
... 
ID=1210 
ID=1211 
ID=1212 
ID=1301 
+0

是否需要本地声明?另外,你能解释为什么我们需要%let语句吗?为什么不''让tmp_date =%sysfunc(intnx(month,&iStart_date,0,beginning))'工作,用&替换0并且让i = x(月数)? – DukeLuke

+0

代码将在没有'%local'语句的情况下运行,但是这会使其对宏定义范围问题开放。最好的做法是始终用'%local'语句定义该宏的局部变量。在这种特殊情况下,技术上只需要第二个'%let'。我把他们俩都放在那里,因为当我回到学校时(初始化外部值,然后在循环内迭代它),它被敲入我的正确结构中作为一段时间循环。是的,你可以重新创建一个'%do'循环;有很多替代方法可以编写代码,做最适合你的方法=) –

+1

@DukeLuke如果您想了解更多关于宏观范围的知识,请访问http://support.sas.com/documentation /cdl/en/mcrolref/67912/HTML/default/viewer.htm#n10i4tmalsyhgxn1hj4ud13ff074.htm –

2

这里是做这样一个循环的一种方式:

%macro month_loop(MTH_FROM, MTH_TO); 
    %local T_MTH_FROM T_MTH_TO MTH_DIFF CUR_MTH MTH_OFFSET; 
    %let T_MTH_FROM = %sysfunc(inputn(&MTH_FROM,yymmn.)); 
    %let T_MTH_TO = %sysfunc(inputn(&MTH_TO,yymmn.)); 
    %let MTH_DIFF = %sysfunc(intck(month,&T_MTH_FROM,&T_MTH_TO)); 

    %do MTH_OFFSET = 0 %to &MTH_DIFF; 
    %let CUR_MTH = %sysfunc(intnx(month,&T_MTH_FROM,&MTH_OFFSET), yymmn4.); 
    %put CUR_MTH = &CUR_MTH; 
    %end; 
%mend; 

%month_loop(1001,1607); 
0

这是一个有点难以跟随你的逻辑,但它看起来像你只想做:

data final; 
    set appd.file work01-work03 ; 
run; 
+0

如果SAS允许在数据集上使用'--'匹配而不是仅使用变量,那么这将起作用。 '-'匹配会有问题,因为在1012和1101之间的每月数据集之间会有差距,'-'不支持差距。 –