我的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)
答案 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一样,比宏循环更容易 - 但它并不一定会在这些情况下添加。
假设您有2) - 您在WORK库中有DATASET_201301
到DATASET_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'
。