当我使用PROC EXPORT时,如何阻止SAS向每个字符串变量添加额外的空字节?

当我使用PROC EXPORT时,如何阻止SAS向每个字符串变量添加额外的空字节?,sas,stata,Sas,Stata,当我使用PROC export将数据集导出为Stata格式时,SAS 9.4会自动展开,为每个字符串变量的每个观察值添加一个额外的(空)字节。例如,在此数据集中: data test1; input cust_id $ 1 month 3-8 category $ 10-12 status $ 14-14 ; datalines; A 200003 ABC C A 200004 DEF C A 2000

当我使用
PROC export
将数据集导出为Stata格式时,SAS 9.4会自动展开,为每个字符串变量的每个观察值添加一个额外的(空)字节。例如,在此数据集中:

data test1;
    input cust_id   $ 1
          month       3-8
          category  $ 10-12 
          status    $ 14-14
;
datalines;
A 200003 ABC C
A 200004 DEF C
A 200006 XYZ 3
B 199910 ASD X
B 199912 ASD C
;
quit;

proc export data = test1
    file = "test1.dta"
    dbms = stata replace;
quit;
变量
cust\u id
category
status
应该是最终Stata文件中的
str1
str3
str1
,因此每次观察分别占用1字节、3字节和1字节。但是,SAS会自动向每个观测值添加一个额外的空字节,从而将其数据类型扩展为输出的Stata文件中的
str2
str4
、和
str2
数据类型

这是非常有问题的,因为这是一个额外的字节添加到每个字符串变量的每个观察。对于大型数据集(我有一些具有约5.3亿个观测值和大量字符串变量),这可以向导出的文件中添加几GB

一旦文件加载到Stata中,Stata中的
compress
命令可以自动删除这些空字节并收缩文件,但对于大型数据集,
PROC EXPORT
会向文件中添加太多额外字节,因此我首先没有足够的内存将数据集加载到Stata中


有没有一种方法可以首先阻止SAS填充字符串变量?例如,当我导出一个带有一个字符串变量的文件时,我希望该变量作为一个字符串变量存储在输出文件中

如果您愿意接受平面文件答案,我想出了一个相当简单的方法来生成一个我认为具有您需要的属性的答案:

data test1;
    input cust_id   $ 1
          month       3-8
          category  $ 10-12 
          status    $ 14-14
;
datalines;
A 200003 ABC C
A 200004 DEF C
A 200006 XYZ 3
B 199910 SD  X
B 199912 D   C
;
run;

data _null_;
file "/folders/myfolders/test.txt";
set test1;
put @;
_FILE_ = cat(of _all_);
put;
run;

/* Print contents of the file to the log (for debugging only)*/
data _null_;
 infile "/folders/myfolders/test.txt";
 input;
 put _infile_;
run;
如果数据集中所有变量的总分配长度小于32767(数据步环境中
cat
函数的限制-200个字符的下限不适用,因为只有在使用
cat
创建未分配长度的变量时,才适用此限制)。除此之外,您可能会开始遇到截断问题。发生这种情况时的一个解决方法是一次只将有限数量的变量组合在一起,这是一个手动过程,但比根据所有变量的长度写出put语句要省力得多,而且根据您的数据,它可能永远不会出现


或者,您可以使用更复杂的宏路径,从
vlength
函数或
dictionary.columns
获取可变长度,并使用这些列和变量名来构造所需的
put
语句。

这就是使用现有函数的方法

filename FT41F001 temp;
data _null_;
   file FT41F001;
   set test1;
   put 256*' ' @;
   __s=1;
   do while(1);
      length __name $32.;
      call vnext(__name);
      if missing(__name) or __name eq: '__' then leave;
      substr(_FILE_,__s) = vvaluex(__name);
      putlog _all_;
      __s = sum(__s,vformatwx(__name));
      end;
   _file_ = trim(_file_);
   put;
   format month f6.;
   run;
避免使用u文件u

data _null_;
   file FT41F001;
   set test1;
   __s=1;
   do while(1);
      length __name $32. __value $128 __w 8;
      call vnext(__name);
      if missing(__name) or __name eq: '__' then leave;
      __value = vvaluex(__name);
      __w = vformatwx(__name);
      put __value $varying128. __w @;
      end;
   put;
   format month f6.;
   run;

我怀疑SAS正在添加字符串终止符,尽管我不知道为什么。查看Stata文档,它确实支持
\0
字符串终止符(用于“Varchar”类型的操作)。我猜SAS只是把它放在每个字符串后面,如果我不得不猜的话。我建议您在SAS技术支持中加入支持票证;他们可能会a)确认这一点,b)让您知道是否有解决办法。我没有看到一个简单的搜索结果。如果您确实收到SAS技术支持的回复,请添加一个答案,其中包含您获得的任何信息,以便其他搜索者可以使用!如果有比压缩更好的stata端解决方案,则添加。SAS和stata都可以输入/输出固定字段宽度的文本文件。如果以足够精度的数字形式传递数值数据不会占用太多空间,这就解决了您的问题。我喜欢您让CAT格式化行的想法,但它不适用于数值变量。不能依靠数字到字符的转换来生成相同宽度的值。(我认为)使这项工作起作用的是一个CAT函数版本,它使用VVALUE函数格式化所有变量。@data\u null\u不幸的是,不存在这种假设的
catv
函数,并且
VVALUE
和类似函数不能在
proc fcmp
定义中使用,因为它们仅在数据步骤中有效。需要一些数组和宏逻辑来将数字变量转换为固定宽度的文本。
call vnext
vformatwx
是我所缺少的拼图块,如果没有它们,要将所有内容整齐地放在一起要困难得多。但是,最好还是避免使用
\u file
,因为这将每个输出行限制为32767个字符。我还建议在最后的整理步骤中使用
substr
而不是
trim
,因为这将避免从源数据集中的最后一个变量中删除任何有效的尾随空格。现在看起来非常好-我唯一要做的调整是设置
lrecl=1000000
或类似设置,以避免长输出行被截断为默认长度。