强制 proc export 为不存在的变量创建空白列

Forcing proc export to create blank column for non-existing variable

背景

我运行下面的宏在循环中导出了一些数据集。不幸的是,其中一些数据集有额外的变量。我的目的是以相同格式导出所有文件,其中 不存在的列作为空白提供

数据

这可以用以下数据集来说明。

dataA

varA varB
1    3
2    3
3    3

dataB

varA varB
9    4
9    4
9    4

dataC

varA varB varC
2    5    6
2    5    6
2    5    6

我希望我的 CSV 文件如下所示:

dataA.CSV

varA varB varC
1    3    .
2    3    .
3    3    .

dataB.CSV

varA varB varC
9    4    .
9    4    .
9    4    .

dataC.CSV

varA varB varC
2    5    6
2    5    6
2    5    6

%macro export_data(dsnms);
    * Get observations count;
    PROC SQL;
        SELECT COUNT(*) INTO :obscount
            FROM &dsnms;
    QUIT;

    * Export all available files in the loop;
    %Local D;

    %DO D = 1 %TO &obscount;

        * Print progress message;
        sysecho "Progressing through &D of &obscount";

        * Get table name;
        PROC SQL;
            SELECT COMPRESS(MEMNAME) INTO: Table
                FROM &dsnms
                    WHERE rownum=&D;
        QUIT;

        * Extra spaces in file name are removed via cmpres call;
        PROC EXPORT DBMS=CSV DATA=SASLIBWITHSTUFF.&Table
            OUTFILE="/mystuff/%cmpres(&Table).csv";
        RUN;

        * Inform about succesful export;
        sysecho "Created &Table..csv export file.";
    %END;
%mend;

总结

换句话说,如果这样的话,我想修改 proc export 的行为来创建 NonExistingVarKepp = 中传递。当然,这会失败,因为 sashelp.class 没有 NonExistingVar 但这是我想要模仿的行为。

proc export data=sashelp.class (keep =  name
                                        sex
                                        NonExistingVar)
   outfile="/stuff/proc_test.csv"
   dbms=csv
   replace;
run;

如果您在某个地方有一个包含要导出的列列表的宏变量,您可以构建一个包含它们的视图,包括基础数据集中不存在的那些,然后导出视图.例如

%let keepcols = sex weight newcol;

data t_view /view = t_view;
  if 0 then set sashelp.class; 
  if _n_ = 1 then call missing(of &keepcols);
  set sashelp.class;
run;

if 0 then set xyz 是一个不错的小技巧,它允许您保留列顺序、长度和类型,而无需从第一个 set 语句中读取任何行。它避免了随后将变量设置为缺失值时的类型冲突——我们必须将它们初始化为 something 否则它们不会输出。第二个 set 语句将覆盖实际存在的变量的缺失值。

如果您查询元数据表以确定保留的哪些列存在,这可能会更有效一些,因此您只会加载那些列,但这在大多数情况下应该是合理的。

一个更懒惰的选项是暂时禁用与 keep 相关的错误和警告,例如:

%let keepcols = sex weight newcol;

%let dkricond = %sysfunc(getoption(dkricond)); /*Save for later*/
option dkricond = nowarn;

data t_view /view = t_view;
  if 0 then set sashelp.class(keep = &keepcols); /*Normally this would trigger an error or warning*/
  retain &keepcols;
  set sashelp.class(keep = &keepcols); 
run;

option dkricond = &dkricond; /*Restore original setting*/

为此,您需要有一个要输出的变量列表。因此,让我们假设您有一个带有该列表的宏变量。

%let varlist=varA varB varC ;

由于您正在编写 CSV 文件,因此您可以直接使用 DATA 步骤执行此操作,而避免使用 PROC EXPORT。在数据步骤中,如果您引用一个不存在的变量,那么 SAS 会很乐意为您创建一个空变量。

您可能需要有点创意才能添加 header 记录。这是一种使用 TRANWRD() 函数的方法,当您在每个变量名称之间只有一个 space 时,该函数有效。请注意,您可以使用 COMPBL() 来实现这一点。

%let varlist=Name Unknown    Age ;
%let varlist=%sysfunc(compbl(&varlist));

data _null_;
  file "/stuff/proc_test.csv" dsd ;
  if _n_=1 then put "%sysfunc(tranwrd(&varlist,%str( ),%str(,)))" ;
  set sashelp.class ;
  put &varlist ;
run;

结果:

Name,Unknown,Age
Alfred,,14
Alice,,13
Barbara,,13
Carol,,14
Henry,,14
James,,12
Jane,,12
Janet,,15
Jeffrey,,13
John,,12
Joyce,,11
Judy,,14
Louise,,12
Mary,,15
Philip,,16
Robert,,12
Ronald,,15
Thomas,,11
William,,15