基于包含元数据的文件构建SAS数据集
我有两个文本文件,一个包含没有标题的原始数据,另一个包含相关的列名和长度。我想使用这两个文件构建一个SAS数据集,其中包含来自一个文件的数据,以及来自另一个文件的列名和长度 包含数据的文件是固定宽度的文本文件。也就是说,每列数据都与文本文件的特定列对齐,并用空格填充以确保对齐 datafile.txt:基于包含元数据的文件构建SAS数据集,sas,metadata,sas-macro,Sas,Metadata,Sas Macro,我有两个文本文件,一个包含没有标题的原始数据,另一个包含相关的列名和长度。我想使用这两个文件构建一个SAS数据集,其中包含来自一个文件的数据,以及来自另一个文件的列名和长度 包含数据的文件是固定宽度的文本文件。也就是说,每列数据都与文本文件的特定列对齐,并用空格填充以确保对齐 datafile.txt: John 45 Has two kids Marge 37 Likes books Sally 29 Is an astronaut Bill 60 Drinks c
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
语句,如下所示:
/*导入元数据*/
元数据;
长度colname$50科伦8;
infle'C:\metadata.txt'dsd dlm='09'x;
输入colname$collen;
跑
/*构造长度和输入语句*/
数据为空;
长度透镜输入1000美元;
保留lenstmt inptstmt“”colstart 1;
设置meta end=eof;
调用catx(“”,lenstmt,colname,“$”,colen);
调用catx(“”,inptstmt,cats(“@”,colstart),colname,“$&”);
colstart+collen;
如果是eof,那么做;
调用symputx('lenstmt',lenstmt);
调用symputx(“inptstmt”,inptstmt);
结束;
跑
/*导入数据文件*/
数据文件;
长度&透镜;
填充'C:\datafile.txt'dsd dlm='09'x;
输入&inptstmt;
跑
这让我得到了我需要的,但必须有一个更干净的方法。如果为存储length
和input
语句的变量分配的空间不足,或者如果语句长度超过了最大宏变量长度,这种方法可能会遇到麻烦
有什么想法吗?请打电话给我,我可以帮忙
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;
你所做的是一种相当标准的方法。是的,你可以更仔细地检查;例如,为了谨慎起见,我会为这两条语句分配32767美元 不过,有一些方法可以改善这一点,这可能会消除你的一些担忧 首先,一个常见的解决方案是在行级别构建它(正如您所做的),然后使用
proc sql
创建宏变量。这比数据步方法有更大的最大长度限制(数据步方法的最大长度是32767美元,如果不使用多个变量,SQL是64kib的两倍)
其次,您可以通过写入文件而不是宏变量来超过64k限制。在数据步骤中,不要累加然后使用call symput
,而是将每一行写入一个temp
文件(或两个)。然后,<>代码> %>代码>那些文件,而不是在输入数据步中使用宏变量——是的,你可以<代码> %包含在数据步中间的。< /P>
还有其他方法,但这两种方法是最常见的,应该适用于大多数用例。其他一些方法包括
callexecute
、run\u macro
,或使用文件打开命令直接处理文件。一般来说,这两种方法要么比最常见的两种方法更复杂,要么没有那么有用,尽管它们当然也是可以接受的解决方案,在实践中并不少见。为什么这比OP的例子更干净?如果你认为这是一种改进,请在答案中解释原因,并提供更多信息。@Joe-我认为问题的最后部分回答了为什么我的解决方案更干净。实现此解决方案的用户不需要担心任何大小限制。此外,不会浪费任何数据步骤,也不会创建任何浪费的宏变量。我不反对宏,但我喜欢在需要时使用它们。使用基于调用执行的解决方案,用户无需担心datastep变量大小或宏变量大小限制。然后将其放入您的答案中。你的答案基本上就是代码。仅仅是代码的答案不是很好的答案-他们应该解释它们是如何工作的(至少在某种程度上)以及为什么它们应该为手头的问题工作。是否有一种方法也可以使用proc sql
完成运行求和,从而在input
语句中获取输入列?或者,这应该在数据步骤中提前完成?这是您希望提前完成的。对于这种特殊情况,我可能会使用%include
方法。
proc sql;
select catx(' ',colname,'$',collen)
into :lenstmt separated by ' '
from meta; *and similar for inputstmt;
quit;