通常在多次尝试导入过程失败后,我决定最好避免这样做,因为它有时会产生令人惊讶的结果。
您可以改为在数据步内使用 infile 命令:
data input_data;
infile "../../file.txt"
firstobs = 2
dlm = " "
missover
dsd
lrecl = 32767
input
var1 : $char128. /*string field of 128 chars long*/
var2 : best32. /*numbers of all types ints, floats, etc */
...
/*do this for every variable (column) in you .txt file */
;
run;
上面的代码或多或少是 proc 导入所做的。 proc import 的问题在于它试图“猜测”正确的选项(例如 dsd、missover 等)和数据类型,但并不总是成功。您可以找到更多关于这些选项的作用here。
例如,missover 选项告诉 sas 在找到两个连续分隔符时要做什么。 (这应该被视为一个空列,并在读取下一个值时将一个值留空,还是只拉入下一个可用值?)
当然,上面的代码在包含大量列的长 txt 文件的情况下不是很实用,因为您必须自己键入每个列标签及其数据类型。
一个可能的解决方案是:
data headers;
infile "../../file.txt"
firstobs = 1
obs = 1
dlm = "_" /*make sure to here to use a delimiter DIFFERENT from the real one to keep everything in one observation*/
missover
lrecl = 32767
input
whole_line : $char32767.
;
run;
上述步骤创建了一个数据集,其中包含一个观察值,其中包含由分隔符分隔的所有列标题。
现在你可以使用了:
proc sql noprint;
select distinct tranwrd(compress(line),","," ") as lineTest length=32767 into: headers from headers length;
quit;
上面的代码创建了一个名为 headers 的宏变量,其列名由空格分隔(tranwrd() 函数基本上将 ',' 替换为 ' ' 因为我通常使用 csv 文件,所以这对你来说可能不是必需的. 一般来说,使用空格作为分隔符可能不是一个好主意 - 如果您的字符串字段本身包含空格,则适用。您得到的错误实际上可能与此有关)
现在您可以循环访问宏变量,而不是编写每个列名并一一键入:
data inputFile (compress=binary) ;
infile "../../file.txt"
dsd
dlm = ","
lrecl = 32767
firstobs = 2
;
input
%do i=1 %to %words(&headers);
%let currCol = %scan(&headers. , &i.);
&currCol : $char256.
%end;
;
run;
这将创建您想要的数据集,而无需担心文件结构是否已更改(添加或删除列),这会使您的代码更加动态。当然,这留下了所有值都作为字符导入的问题。
这绝对是个问题,但是我发现按需类型转换变量要容易得多,而不是在输入语句中一个一个地键入每个变量。
如果您将使用宏变量和 %do 循环,请务必将所有代码包含在宏中,否则循环会出错。
我希望这会有所帮助!