SAS:动态确定数据集中的输入字段

SAS: Dynamically determine input fields from a dataset

我正在尝试解析包含 300 多个字段的分隔数据集。而不是像

这样列出所有输入字段
    data test;
    infile "delimited_filename.txt"
            DSD delimiter="|" lrecl=32767 STOPOVER;

    input   field_A:0.
            field_B :0.
            field_C:0.
            /*continues on */
    ;

我想我可以将所有字段名称转储到一个文件中,作为 sas 数据集读入,并填充输入字段 - 如果任何字段名称发生变化,这也给我动态控制(add/remove) 在数据集中。有什么好的方法可以做到这一点?

非常感谢 - 我刚开始使用 sas,仍在努力思考它。

这对我有用 - 基本上 "write" 使用宏语言和 运行 数据打开代码。

注意:我的 indata_header_file 包含 5 列:Variable_Name、Variable_Length、Variable_Type、Variable_Label 和注释。

%macro ReadDsFromFile(filename_to_process, indata_header_file, out_dsname);

%local filename_to_process indata_header_file out_dsname;

/* This macro var contain code to read data file*/
%local read_code input_in_line; 
%put *** Processing file: &filename_to_process ...;

/* Read in the header file */
proc import OUT     = ds_header
        DATAFILE    = &indata_header_file.
        DBMS        = EXCEL REPLACE;        /* REPLACE flag */
        SHEET       = "Names";
        GETNAMES    = YES;
        MIXED       = NO;
        SCANTEXT    = YES; 
run;

%let id     = %sysfunc(open(ds_header));
%let NOBS   = %sysfunc(attrn(&id.,NOBS)); 
%syscall set(id); 

/* 
    Generates:
    data &out_dsname.;
    infile "&filename_to_process."
        DSD delimiter="|" lrecl=32767 STOPOVER FIRSTOBS=3;  
        input   
        '7C'x
*/

%let read_code = data &out_dsname. %str(;)
                        infile &filename_to_process.
                        DSD delimiter=%str("|") lrecl=32767 STOPOVER %str(;)
                        input ;

/*
    Generates:
    <field_name> : $<field_length>;
*/
%do i = 1 %to &NObs;
    %let rc             = %sysfunc(fetchobs(&id., &i));
    %let VAR_NAME       = %sysfunc(getvarc(&id., %sysfunc(varnum(&id., Variable_Name)) ));  
    %let VAR_LENGTH     = %sysfunc(getvarn(&id., %sysfunc(varnum(&id., Variable_Length)) ));    
    %let VAR_TYPE       = %sysfunc(getvarc(&id., %sysfunc(varnum(&id., Variable_Type)) ));  
    %let VAR_LABEL      = %sysfunc(getvarc(&id., %sysfunc(varnum(&id., Variable_Label)) ));
    %let VAR_NOTES      = %sysfunc(getvarc(&id., %sysfunc(varnum(&id., Notes)) ));      

    %if %upcase(%trim(&VAR_TYPE.)) eq CHAR %then 
        %let input_in_line = &VAR_NAME :$&VAR_LENGTH..;
    %else
        %let input_in_line = &VAR_NAME :&VAR_LENGTH.;

    /* append in_line statment to main macro var*/
    %let read_code = &read_code. &input_in_line. ;
%end; 

/* Close the fid */
%let rc = %sysfunc(close(&id));

%let read_code = &read_code. %str(;) run %str(;) ;

/* Run the generated code*/
&read_code.

%mend ReadDsFromFile;

听起来您想基于元数据生成代码。数据步骤实际上比宏更容易编码和调试。 假设您有描述输入数据的元数据。例如,让我们使用关于 SASHELP.CARS 的元数据。我们可以从现有数据集上的现有 DICTIONARY.COLUMNS 元数据构建我们的元数据。让我们将 INFORMAT 设置为 FORMAT,因为 table 没有分配 INFORMAT 值。

proc sql noprint ;
 create table varlist as
   select memname,varnum,name,type,length,format,format as informat,label
   from dictionary.columns
   where libname='SASHELP' and memname='CARS'
 ;
quit;

现在让我们制作一个包含数据的示例文本文件。

filename mydata temp;
data _null_;
  set sashelp.cars ;
  file mydata dsd ;
  put (_all_) (:);
run;

现在我们只需要使用元数据编写一个可以读取该数据的程序。我们真正需要做的就是定义变量,然后添加一个简单的 INPUT firstvar -- lastvar 语句来读取数据。

filename code temp;
data _null_;
  set varlist end=eof ;
  by varnum ;
  file code ;
  if _n_=1 then do ;
    firstvar=name ; 
    retain firstvar ;
    put 'data ' memname ';'
      / '  infile mydata dsd truncover lrecl=1000000;'
    ;
  end;
  put '  attrib ' name 'length=' @;
  if type = 'char' then put '$'@ ;
  put length ;
  if informat ne ' ' then put @10 informat= ;
  if format ne ' ' then put @10 format= ;
  if label ne ' ' then put @10 label= :$quote. ;
  put '  ;' ;
  if eof then do ;
    put '  input ' firstvar '-- ' name ';' ;
    put 'run;' ;
  end;
run;

现在我们可以 运行 使用 %INCLUDE 生成的代码。

%include code / source2 ;