有時(shí)為了解項(xiàng)目數(shù)據(jù)結(jié)構(gòu)述么,需要查看不少原始數(shù)據(jù)。簡(jiǎn)單的記錄篩選愕掏,SAS操作起來不復(fù)雜度秘,但是對(duì)于大批量數(shù)據(jù)記錄的查看,SAS篩選就顯得繁瑣亭珍。這種情況下敷钾,將數(shù)據(jù)集批量輸出到Excel中進(jìn)行查看,不失為一個(gè)很好的方法肄梨。
數(shù)據(jù)集批量輸出的要達(dá)到什么效果呢?出于篩選方便的考慮挠锥,所有數(shù)據(jù)集保存在一個(gè)Excel文件中众羡,數(shù)據(jù)集名稱作為對(duì)應(yīng)的Sheet名稱,每個(gè)表單凍結(jié)首行蓖租,并且直接設(shè)置首行篩選粱侣。
這樣打開Excel文件,就可以不需要額外設(shè)置蓖宦,可以直接瀏覽齐婴、篩選數(shù)據(jù)。
在SAS編程中稠茂,常見的批量處理的方法有兩種柠偶,一是宏程序中的宏循環(huán),二是call execute
語句睬关。
下面介紹整個(gè)輸出的實(shí)現(xiàn)過程诱担,先從單個(gè)數(shù)據(jù)集輸出開始。
1. 單個(gè)數(shù)據(jù)集的輸出
SAS程序參考之前的文章SAS編程:輸出SAS數(shù)據(jù)集(Listing)到EXCEL电爹。通常蔫仙,使用export
過程步,進(jìn)行簡(jiǎn)單的輸出丐箩;使用ods excel
語句以及report
過程步摇邦,進(jìn)行復(fù)雜的輸出設(shè)置恤煞,例如,凍結(jié)標(biāo)題施籍、首行自動(dòng)篩選等
ods excel file = "E:\999_test.xlsx"
options(sheet_name="Class" frozen_headers="Yes" autofilter = "Yes");
proc report data = sashelp.class;
column _all_;
run;
ods excel close;
輸出結(jié)果如下:
單個(gè)數(shù)據(jù)集實(shí)現(xiàn)了對(duì)應(yīng)格式的輸出阱州。
2. 兩個(gè)數(shù)據(jù)集的輸出
還是參考之前的文章,第二個(gè)ods excel
語句輸出不添加file=
語句法梯,這樣兩個(gè)數(shù)據(jù)集就輸出到同一個(gè)Excel文件的不同sheet中苔货。
ods excel file = "E:\999_test\test.xlsx"
options(sheet_name="Class" frozen_headers="Yes" autofilter = "Yes");
proc report data = sashelp.class;
run;
ods excel
options(sheet_name="Cars" frozen_headers = "Yes" autofilter="Yes");
proc report data = sashelp.cars;
column _all_;
run;
ods excel close;
3個(gè)及以上數(shù)據(jù)集的輸出,與此類似立哑。
3. 邏輯庫內(nèi)所有數(shù)據(jù)集的輸出
顯然夜惭,如果照著上面舉例手動(dòng)添加數(shù)據(jù)集的輸出程序,輸出邏輯庫中的所有數(shù)據(jù)集的過程就太過繁瑣铛绰,所以需要批量處理诈茧。
常見的批量處理的方法有兩種,一是宏循環(huán)捂掰,二是call execute
語句敢会。下面來介紹這兩種方法的實(shí)現(xiàn)。
不管哪種方法这嚣,首先需要獲取邏輯庫中的數(shù)據(jù)集名稱鸥昏,以方便引用。這里姐帚,以SASHelp邏輯庫中前10個(gè)數(shù)據(jù)集進(jìn)行舉例吏垮。
**Get datasets' names;
data tables;
set sashelp.vtable;
where libname = "SASHELP";
if _n_ <= 10;
keep libname memname;
run;
輸出結(jié)果如下:
3.1 宏循環(huán)批量輸出數(shù)據(jù)集
SAS宏可以理解成是“代碼生成器”,宏程序的批量處理是通過宏循環(huán)實(shí)現(xiàn)罐旗。
參考兩個(gè)數(shù)據(jù)集輸出的代碼膳汪,對(duì)于不同數(shù)據(jù)集,sheet_name=
與data=
選項(xiàng)值是變化的九秀∫潘裕考慮到SAS數(shù)據(jù)集名稱是不區(qū)分大小寫,這兩個(gè)選項(xiàng)值可以看作是相同的鼓蜒。
宏循環(huán)的思路是痹换,將數(shù)據(jù)集的名稱保存到各個(gè)宏變量中,這些宏變量名稱的前綴相同友酱,后綴以序號(hào)結(jié)尾晴音。這里我將其稱為,宏變量序列缔杉。獲取宏變量序列后锤躁,利用循環(huán)變量,從而實(shí)現(xiàn)“代碼生成”的效果或详。
3.1.1 宏變量序列的生成
宏變量序列的生成常用也有2種方法:
- Proc SQL 中的
into :
語句- Data步中的
call symputx
語句
3.1.1.1 Proc SQL生成宏變量序列
into :
語句之前介紹過系羞,可以參考SAS編程:Proc SQL生成宏變量時(shí)INTO子句的使用 郭计。使用這個(gè)方法,需要獲取數(shù)據(jù)集的記錄數(shù)椒振,這里就不介紹如何獲取數(shù)據(jù)集的記錄數(shù)了昭伸,直接手動(dòng)賦值為10。
**Save tables' names in macro vars by sql;
proc sql noprint;
select memname
into :memname1- :memname10
from tables;
quit;
%put memname1 = &memname1.;
%put memname10 = &memname10.;
輸出結(jié)果如下:
3.1.1.2 Data 步中生成宏變量序列
與SQL中依靠后綴序列進(jìn)行計(jì)數(shù)不同澎迎,Data步中數(shù)據(jù)集自帶的自動(dòng)變量_n_
可以實(shí)現(xiàn)計(jì)數(shù)的功能庐杨。
**Save tables' names in macro vars by data step;
data _null_;
set tables;
call symputx("name"||strip(put(_n_, best.)), strip(memname));
run;
%put memname1 = &name1.;
%put memname10 = &name10.;
輸出結(jié)果與SQL結(jié)果一致,可以看出Data步方法實(shí)現(xiàn)可以省去獲取數(shù)據(jù)集記錄數(shù)的步驟夹供,整體上代碼比較簡(jiǎn)潔灵份。
3.1.2 宏循環(huán)批量輸出數(shù)據(jù)集
宏循環(huán)需要處理,第一個(gè)數(shù)據(jù)集與其他數(shù)據(jù)集輸出的不同(后續(xù)數(shù)據(jù)集不需要file=
選項(xiàng))哮洽,用判斷語句進(jìn)行區(qū)分填渠。
如果想要查看宏程序具體的運(yùn)行代碼,可以參考文章SAS編程:檢查宏程序issue思路介紹鸟辅,里面有對(duì)mprint
選項(xiàng)的介紹氛什。
調(diào)試程序的時(shí)候,發(fā)現(xiàn)SASHelp.BIRTHWGT
這個(gè)數(shù)據(jù)集居然有10萬條記錄匪凉,ods excel
語句輸出會(huì)出現(xiàn)內(nèi)存不足等問題枪眉,于是使用ods tagsets.excelxp
進(jìn)行輸出。
**Export datasets to Excel file using macro loop;
%macro loop;
%do a = 1 %to 10;
%if &a. = 1 %then %do;
ods tagsets.excelxp file = "E:\999_test\test.xlsx"
options(sheet_name="&name1." frozen_headers="Yes" autofilter = "Yes");
proc report data = sashelp.&name1.;
column _all_;
run;
%end;
%else %do;
ods tagsets.excelxp options(sheet_name="&&name&a." frozen_headers = "Yes" autofilter="Yes");
proc report data = sashelp.&&name&a.;
column _all_;
run;
%end;
%end;
ods tagsets.excelxp close;
%mend;
%loop;
問題處理
但使用ods tagsets.excelxp
有會(huì)出現(xiàn)一個(gè)問題洒缀,輸出文件用Excel打開的話瑰谜,會(huì)顯示如下內(nèi)容,無法打開文件:
WPS可以正常打開輸出文件树绩,10個(gè)數(shù)據(jù)集完整的輸出到Excel文件中。
也可以使用.xls
作為輸出文件的后綴隐轩,這時(shí)文件可以用Excel打開饺饭,不過會(huì)有Warning提示。
ods tagsets.excelxp file = "E:\999_test\test.xls"
ods tagsets.excelxp close;
還有一個(gè)退而求其次的方法职车,舍棄Excel的設(shè)置瘫俊,使用export
過程步,進(jìn)行簡(jiǎn)單的輸出悴灵,不進(jìn)行Excel的屬性設(shè)置扛芽,后續(xù)再使用VBA對(duì)各個(gè)Sheet進(jìn)行批量屬性設(shè)置。
%macro loop;
%do a = 1 %to 10;
proc export data=sashelp.&&name&a.
outfile='E:\999_test\test.xlsx'
dbms=xlsx replace;
sheet = "&&name&a.";
run;
%end;
%mend;
%loop;
3.2 call execute()
批量輸出數(shù)據(jù)集
3.2.1 call execute()
的簡(jiǎn)單介紹
官方文檔是這樣积瞒,介紹call execute()
語句的:
Resolves the argument, and issues the resolved valuefor execution at the next step boundary.
(解析參數(shù)川尖,并發(fā)出已解析的值以便在下一步邊界執(zhí)行。)
call execute()
是為了在Data步中執(zhí)行其他完整的SAS代碼茫孔,括號(hào)里面的內(nèi)容是一段完整的字符串叮喳,舉個(gè)簡(jiǎn)單的例子被芳。
data _null_;
call execute(
'
data class;
set sashelp.class;
run;
'
);
run;
以上的代碼就是直接引號(hào)中的程序。這里讀者可能會(huì)有疑問馍悟,直接寫一遍引號(hào)中的代碼再運(yùn)行畔濒,不是更方便嗎?
單從直接調(diào)用簡(jiǎn)單的SAS程序來講锣咒,這確實(shí)是多此一舉侵状。但是,call execute()
是可以直接調(diào)用數(shù)據(jù)集中的記錄值毅整,進(jìn)行運(yùn)行趣兄。再舉個(gè)例子:
data tmp;
a = "class";
run;
data _null_;
set tmp;
call execute(
'
data class;
set sashelp.'||strip(a)||';
run;
'
);
run;
以上程序運(yùn)行的結(jié)果,是解析數(shù)據(jù)集Tmp中變量a的值毛嫉,帶入引號(hào)中的程序诽俯。可以這樣理解承粤,括號(hào)中的內(nèi)容依舊是一個(gè)待運(yùn)行的字符串暴区,只不過這個(gè)字符串拼接了Tmp數(shù)據(jù)集中變量a的值。
讀者看到這里可能又會(huì)有疑問辛臊,如果數(shù)據(jù)集中有多條數(shù)據(jù)仙粱,call execute()
將如何處理呢?
如果數(shù)據(jù)集中有多條數(shù)據(jù)彻舰,call execute()
就會(huì)運(yùn)行多次程序伐割,按數(shù)據(jù)集記錄的行數(shù)進(jìn)行迭代,每一次運(yùn)行的程序會(huì)更新"變量a"的值刃唤。
如果Tmp數(shù)據(jù)集中有2條記錄隔心,class
, cars
,那么最后執(zhí)行的代碼如下:
data class;
set sashelp.class;
run;
data class;
set sashelp.cars;
run;
3.2.2 call execute()
批量輸出數(shù)據(jù)集到EXCEL
有了上面的介紹尚胞,直接看批量輸出數(shù)據(jù)集的代碼:
data _null_;
set tables end = eof;
if _n_ = 1 then call execute(
'
ods tagsets.excelxp file = "E:\999_test\test.xlsx"
options(sheet_name="'||strip(memname)||'" frozen_headers="Yes" autofilter = "Yes");
proc report data = sashelp.'||strip(memname)||';
column _all_;
run;
'
);
else call execute(
'
ods tagsets.excelxp
options(sheet_name="'||strip(memname)||'" frozen_headers="Yes" autofilter = "Yes");
proc report data = sashelp.'||strip(memname)||';
column _all_;
run;
'
);
if eof then call execute(
'
ods tagsets.excelxp close;
'
);
run;
程序中硬霍,通過_n_
這個(gè)自動(dòng)變量進(jìn)行區(qū)分是否是第一條記錄,然后進(jìn)行對(duì)應(yīng)的設(shè)置笼裳;end = eof
選項(xiàng)唯卖,新建eof變量用于判斷記錄是否到達(dá)尾行,尾行需要將輸出進(jìn)行關(guān)閉躬柬。
輸出結(jié)果與前面SQL一致:
總結(jié)
文章介紹了2種將數(shù)據(jù)集批量輸出到Excel中的方法拜轨,宏循環(huán)和call execute()
語句。宏循環(huán)允青,是先將所有數(shù)據(jù)集名稱保存到宏變量序列中橄碾,然后通過宏循環(huán)進(jìn)行調(diào)用。call execute()
語句,是通過獲取數(shù)據(jù)集變量值構(gòu)建完整的運(yùn)行程序堪嫂。
本質(zhì)上偎箫,宏循環(huán)和call execute()
語句作用是相同的,都是“代碼生成器”皆串。
在介紹宏循環(huán)實(shí)現(xiàn)的過程中淹办,還介紹了2種生成宏變量序列的方法。
感謝閱讀恶复, 歡迎關(guān)注:SAS茶談怜森!
若有疑問,歡迎評(píng)論交流谤牡!