美文网首页
SAS编程:如何将数据集批量输出到Excel?

SAS编程:如何将数据集批量输出到Excel?

作者: 野藤_ | 来源:发表于2022-08-03 18:28 被阅读0次

有时为了解项目数据结构,需要查看不少原始数据。简单的记录筛选,SAS操作起来不复杂,但是对于大批量数据记录的查看,SAS筛选就显得繁琐。这种情况下,将数据集批量输出到Excel中进行查看,不失为一个很好的方法。

数据集批量输出的要达到什么效果呢?出于筛选方便的考虑,所有数据集保存在一个Excel文件中,数据集名称作为对应的Sheet名称,每个表单冻结首行,并且直接设置首行筛选

这样打开Excel文件,就可以不需要额外设置,可以直接浏览、筛选数据。

在SAS编程中,常见的批量处理的方法有两种,一是宏程序中的宏循环,二是call execute语句

下面介绍整个输出的实现过程,先从单个数据集输出开始。

1. 单个数据集的输出

SAS程序参考之前的文章SAS编程:输出SAS数据集(Listing)到EXCEL。通常,使用export过程步,进行简单的输出;使用ods excel语句以及report过程步,进行复杂的输出设置,例如,冻结标题、首行自动筛选等

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;

输出结果如下:

单个数据集实现了对应格式的输出。

2. 两个数据集的输出

还是参考之前的文章,第二个ods excel语句输出不添加file=语句,这样两个数据集就输出到同一个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个及以上数据集的输出,与此类似。

3. 逻辑库内所有数据集的输出

显然,如果照着上面举例手动添加数据集的输出程序,输出逻辑库中的所有数据集的过程就太过繁琐,所以需要批量处理。

常见的批量处理的方法有两种,一是宏循环,二是call execute语句。下面来介绍这两种方法的实现。

不管哪种方法,首先需要获取逻辑库中的数据集名称,以方便引用。这里,以SASHelp逻辑库中前10个数据集进行举例。

**Get datasets' names;
data tables;
  set sashelp.vtable;
  where libname = "SASHELP";

  if _n_ <= 10;
  keep libname memname;
run;

输出结果如下:

Tables
3.1 宏循环批量输出数据集

SAS宏可以理解成是“代码生成器”,宏程序的批量处理是通过宏循环实现

参考两个数据集输出的代码,对于不同数据集,sheet_name=data=选项值是变化的。考虑到SAS数据集名称是不区分大小写,这两个选项值可以看作是相同的。

宏循环的思路是,将数据集的名称保存到各个宏变量中,这些宏变量名称的前缀相同,后缀以序号结尾。这里我将其称为,宏变量序列。获取宏变量序列后,利用循环变量,从而实现“代码生成”的效果。

3.1.1 宏变量序列的生成

宏变量序列的生成常用也有2种方法:

  1. Proc SQL 中的into :语句
  2. Data步中的call symputx语句
3.1.1.1 Proc SQL生成宏变量序列

into :语句之前介绍过,可以参考SAS编程:Proc SQL生成宏变量时INTO子句的使用 。使用这个方法,需要获取数据集的记录数,这里就不介绍如何获取数据集的记录数了,直接手动赋值为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.;

输出结果如下:

3.1.1.2 Data 步中生成宏变量序列

与SQL中依靠后缀序列进行计数不同,Data步中数据集自带的自动变量_n_可以实现计数的功能。

**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.;

输出结果与SQL结果一致,可以看出Data步方法实现可以省去获取数据集记录数的步骤,整体上代码比较简洁

3.1.2 宏循环批量输出数据集

宏循环需要处理,第一个数据集与其他数据集输出的不同(后续数据集不需要file=选项),用判断语句进行区分。

如果想要查看宏程序具体的运行代码,可以参考文章SAS编程:检查宏程序issue思路介绍,里面有对mprint选项的介绍。

调试程序的时候,发现SASHelp.BIRTHWGT这个数据集居然有10万条记录,ods excel语句输出会出现内存不足等问题,于是使用ods tagsets.excelxp进行输出

**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有会出现一个问题,输出文件用Excel打开的话,会显示如下内容,无法打开文件:

image.png

WPS可以正常打开输出文件,10个数据集完整的输出到Excel文件中。

也可以使用.xls作为输出文件的后缀,这时文件可以用Excel打开,不过会有Warning提示。

ods tagsets.excelxp file = "E:\999_test\test.xls" 

ods tagsets.excelxp close;

还有一个退而求其次的方法,舍弃Excel的设置,使用export过程步,进行简单的输出,不进行Excel的属性设置,后续再使用VBA对各个Sheet进行批量属性设置。

%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()批量输出数据集
3.2.1 call execute()的简单介绍

官方文档是这样,介绍call execute()语句的:

Resolves the argument, and issues the resolved valuefor execution at the next step boundary.
(解析参数,并发出已解析的值以便在下一步边界执行。)

call execute()是为了在Data步中执行其他完整的SAS代码,括号里面的内容是一段完整的字符串,举个简单的例子。

data _null_;
  call execute(
  '
  data class;
    set sashelp.class;
  run;
  '
 );
run;

以上的代码就是直接引号中的程序。这里读者可能会有疑问,直接写一遍引号中的代码再运行,不是更方便吗?

单从直接调用简单的SAS程序来讲,这确实是多此一举。但是,call execute()是可以直接调用数据集中的记录值,进行运行。再举个例子:

data tmp;
   a = "class";
run;

data _null_;
  set tmp;
  call execute(
  '
  data class;
    set sashelp.'||strip(a)||';
  run;
  '
 );
run;

以上程序运行的结果,是解析数据集Tmp中变量a的值,带入引号中的程序。可以这样理解,括号中的内容依旧是一个待运行的字符串,只不过这个字符串拼接了Tmp数据集中变量a的值

读者看到这里可能又会有疑问,如果数据集中有多条数据,call execute()将如何处理呢?

如果数据集中有多条数据,call execute()就会运行多次程序,按数据集记录的行数进行迭代,每一次运行的程序会更新"变量a"的值

如果Tmp数据集中有2条记录,class, cars,那么最后执行的代码如下:

 data class;
    set sashelp.class;
 run;

 data class;
    set sashelp.cars;
 run;
3.2.2 call execute()批量输出数据集到EXCEL

有了上面的介绍,直接看批量输出数据集的代码:

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_这个自动变量进行区分是否是第一条记录,然后进行对应的设置;end = eof选项,新建eof变量用于判断记录是否到达尾行,尾行需要将输出进行关闭。

输出结果与前面SQL一致:

总结

文章介绍了2种将数据集批量输出到Excel中的方法,宏循环和call execute()语句。宏循环,是先将所有数据集名称保存到宏变量序列中,然后通过宏循环进行调用。call execute()语句,是通过获取数据集变量值构建完整的运行程序。

本质上,宏循环和call execute()语句作用是相同的,都是“代码生成器”。

在介绍宏循环实现的过程中,还介绍了2种生成宏变量序列的方法。

感谢阅读, 欢迎关注:SAS茶谈!
若有疑问,欢迎评论交流!

相关文章

网友评论

      本文标题:SAS编程:如何将数据集批量输出到Excel?

      本文链接:https://www.haomeiwen.com/subject/yjbjwrtx.html