基于包含元数据的文件构建SAS数据集

时间:2015-03-16 18:18:13

标签: sas metadata sas-macro

我有两个文本文件,一个包含没有标题的原始数据,另一个包含相关的列名和长度。我想使用这两个文件构建一个SAS数据集,其中包含来自一个文件的数据,其中列名和长度来自另一个。

包含数据的文件是固定宽度的文本文件。也就是说,每列数据都与文本文件的特定列对齐,并用空格填充以确保对齐。

datafile.txt:

John   45   Has two kids
Marge  37   Likes books
Sally  29   Is an astronaut
Bill   60   Drinks coffee

包含元数据的文件以制表符分隔,并带有两列:一列具有数据文件中列的名称,另一列具有该列的字符长度。名称按它们在数据文件中的显示顺序列出。

metadata.txt:

Name  7
Age  5
Comments  15

我的目标是拥有一个如下所示的SAS数据集:

Name   | Age  | Comments
-------+------+-----------------
John   | 45   | Has two kids
Marge  | 37   | Likes books
Sally  | 29   | Is an astronaut
Bill   | 60   | Drinks coffee

我希望每个列都是元数据文件中指定长度的字符。

必须有一种比我天真的方法更好的方法,即使用导入的元数据构造length语句和input语句,如下所示:

/* Import metadata */
data meta;
    length colname $ 50 collen 8;
    infile 'C:\metadata.txt' dsd dlm='09'x;
    input colname $ collen;
run;


/* Construct LENGTH and INPUT statements */
data _null_;
    length lenstmt inptstmt $ 1000;
    retain lenstmt inptstmt '' colstart 1;

    set meta end=eof;

    call catx(' ', lenstmt, colname, '$', collen);

    call catx(' ', inptstmt, cats('@', colstart), colname, '$ &');

    colstart + collen;

    if eof then do;
        call symputx('lenstmt', lenstmt);
        call symputx('inptstmt', inptstmt);
    end;
run;


/* Import data file */
data datafile;
    length &lenstmt;
    infile 'C:\datafile.txt' dsd dlm='09'x;
    input &inptstmt;
run;

这让我得到了我需要的东西,但必须有一个更清洁的方式。如果为存储lengthinput语句的变量分配的空间不足,或者语句长度超过最大宏变量长度,则可能会遇到此方法的问题。

有什么想法吗?

2 个答案:

答案 0 :(得分:3)

您正在做的是一种相当标准的方法。是的,你可以更仔细地检查一下;我会为这两个陈述分配$32767,例如,只是为了谨慎。

但是,有一些方法可以改善这一点,这可能会让你担心一些担忧。

首先,一个常见的解决方案是在行级别(就像你那样)构建它,然后使用proc sql来创建宏变量。这比数据步骤方法有更大的最大长度限制(如果不使用多个变量,则数据步骤方法最大值为$32767,SQL为64kib时的两倍)。

proc sql;
  select catx(' ',colname,'$',collen)
    into :lenstmt separated by ' '
    from meta; *and similar for inputstmt;
quit;

其次,通过写入文件而不是宏变量,可以超过64k的限制。获取数据步骤,而不是累积然后使用call symput,将每一行写入temp文件(或两个)。然后%include这些文件而不是在输入datastep中使用宏变量 - 是的,你可以在datastep的中间%include

还有其他方法,但这两种方法是最常见的,应该适用于大多数用例。其他一些方法包括call executerun_macro,或使用文件打开命令直接处理文件。一般来说,这些都比最常见的两个更复杂或更没用,虽然它们也是可接受的解决方案,在实践中并不常见。

答案 1 :(得分:0)

调用execute show可以提供帮助。

data _null_;
retain start 0;
infile 'c:\metadata.txt' missover end=eof;
    if _n_=1 then do; 
        start=1;
        call execute('data final_output; infile "c:\datafile.txt" truncover; input ');
    end;

input colname :$8.
      collen  :8.
      ;

call execute( '@'|| put(start,8. -l) || ' ' || colname || ' $'|| put(collen,8. -r) ||'. ' );
start=sum(start,collen);

    if eof then do;
        call execute(';run;');
    end;
run;
proc contents data=final_output;run;