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 ;
我正在尝试解析包含 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 ;