如何用YYYYMM格式编写几个月的宏循环?

时间:2015-04-23 23:43:12

标签: sas sas-macro

我的SAS工作文件夹中有26个表格,其年份格式为201301-201502(即201301至201312,201401至201412,201501,201502)。我必须创建26个新表,并加入它们(有关详细信息,请参阅下面的示例代码)。

我应该如何循环数据?我打算用一个marco,但不太确定如何循环它。此外,我相信可能有比使用宏更好的方法。

%Macro YearMonth(YM=  );

PROC SQL;
   CREATE TABLE WORK.Join&YM AS 
   SELECT t1.ID, 
      t1.Eff_YM, 
      t1.Trm_YM 

  FROM WORK.DATASET_&YM AS t1 
        LEFT JOIN Work.Names AS t2 
            AND ( input(t1.YearMonth, 6.) = t2.Paid_End_dt2j);
QUIT;
%mend;
%YearMonth(YM = 201301) 
....
%YearMonth(YM = 201502) 

2 个答案:

答案 0 :(得分:4)

在评论中,vol7ron提出了一个重要问题:

  

为什么你有26个桌子?您的数据集中有多少观察?你能不附加到一个数据集中吗?

每个月都有一个单独的数据集表明上游存在问题设计。但是,让我们假设这是你无法控制的。通过宏循环迭代几个月的一种非常简单的方法如下:

%macro loop(start_month=, stop_month=);
    %local month;
    %do month=&start_month %to &stop_month;
        %put Month: &month;

        %* SQL CODE HERE....

        %* SPECIAL CASE WHEN WE REACH END OF A YEAR;
        %if %substr(&month, 5, 2) = 12 %then %let month = %eval(&month + 88);       
    %end;
%mend loop;

%loop(start_month=200301, stop_month=201502)

注意SQL代码的占位符。但是,这个基本模板适用于任何类似的情况。键是%end语句之前的最后一行,它将循环变量增加88,使其从(例如)201312变为201400.然后,控制到达%do循环的顶部,其中&month递增到201401.因此,如果在某个迭代&month等于201312,那么在下一次迭代中它将等于201401。

答案 1 :(得分:1)

一些不同于马修总体答案的笔记。

首先,我强烈建议您将sql代码写入一个单独的宏中,而不是执行循环的宏(如果您甚至使用宏)。它使测试更容易,修改更容易,并且通常是良好的编程习惯。因此,如果你去了一个宏循环的路径,马修有%* PUT SQL CODE HERE;,实际上调用你已经写过的另一个宏。

其次,虽然宏循环方法很好,有时候是正确的方法,但更容易维护的方法是从数据而不是宏循环调用宏。这就是我用95%的代码进行probalby。

在以下情况下,这将明显优越:

  1. 您已经有一个数据集,其中26个月存储为变量(26​​个观察值,每月一个)。不必主要是为了这个目的 - 只要它已经存在于某个地方。
  2. 在某个地方的libname中,您已经拥有这26个数据集(而不是其他您不想要的数据集),其中它们是唯一的数据集,或者只有它们被命名为(更常见)。
  3. 它也可以在其他情况下使用 - 很容易使数据集像上面的1一样,比宏循环更容易 - 但它并不一定会在这些情况下添加。

    假设您有2) - 您在WORK库中有DATASET_201301DATASET_201412,而其他任何标题都不是DATASET_。然后你可以这样使用dictionary.tables

    proc sql;
      select cats('%YearMonth(ym=',scan(memname,2,'_'),')')
        into :callyears separated by ' '
        from dictionary.tables
        where libname='WORK' and memname like 'DATASET_%'
      ;
    quit;
    &callyears.
    

    创建一个宏变量&callyears.,它存储select中的文本 - 在本例中是我们使用连接函数cats创建的宏调用。 memname是数据集名称,libname当然是libname。

    这是使用数据驱动方法调用宏的一种相当简单的方法;这意味着下次你需要运行它时,你不必在这里更改代码中的任何内容 - 只要创建26个数据集之前的代码拉动26个新数据集(或者多个!),你很高兴去。如果你添加第27或第28,它也会自动拉出那些。您可以在where语句中包含一些内容,以便过滤掉当然的内容 - 例如where libname='WORK' and memname like 'DATASET_%' and scan(memname,2,'_') ge '201301'