关于input的columninput (列输入)和listinput (列表输入).

关于input的columninput (列输入)和listinput (列表输入).
简单来说:列输入就是严格按照变量指定的长度进行数据读取,忽略分隔符。如input name 1?10; inputhome40.; 都属于列输入。列表输入就是根据规定的分隔符(默认是空格)按照变量的顺序读取数据,多个空格按照一个处理,遇到空格即停止。如input name home:40. ;
假设有如下原始数据:



需要注意的是,在windows和unix中的文本处理器如写字板创建上面的数据,数据每行属于可变长度,每行的长度就是灰色区域的长度,而在sas的datalines中,上述的数据是固定长度的,长度为80 bytes,后面没数据的地方以空格填充,在大型主机的某些数据文件中,数据行也是固定长度的,无数据的地方以空格填充。

首先分别以input的列输入和列表输入导入上述数据,假设数据位于d盘infile文件夹中,名字为emplist。


DATA test1; /*column input*/
INFILE "d:\infile\emplist.dat";
INPUT lastn $1-21 Firstn $ 22-31
Empid $32-36 Jobcode $37-45;
RUN;

DATA test2; /*list input*/
INFILE "d:\infile\emplist.dat";
INPUT lastn Firstn
Empid Jobcode ;
RUN;

上述程序提交后,结果如何,在此之前,先讲一下flowover选项。Infile默认是flowover选项。
在列输入时:如果input指针到了一行的最后一个字符时,有些变量还是没有得到值或者完整的值,指针就会跳到下一行的第一列开始读取数据,来填充没有值的变量。当下次input语句执行的时候,新的一行数据就会进入inputbuffer。
因此列输入数据如下:




说明,对于第二行数据,pilot没有达到jobcode所需要的长度,因此指针跳到下一行读取smith填补上来。完成之后进入数据步的下一个循环,执行下一次input,因此指针再次跳行,将leistner读入。而读取第五行tomas数据时,harald长度不够firstn用,所以指针跳到下一行将wade读入作为firstn,然后e1026作为empid,pilot仍然不够用,所以跳到下一行读取waugh作为jobcode;
在列表输入时,以空格为分隔符,数据可以正确地读入,但默认的flowover选项仍然会导致将下一行数据读入填充缺失值。结果如下:




使用missover选项:
当在infile语句中使用missover选项时,它会抑制掉flowover,使得在读取短的数据行时,input指针不会跳到下一行来读取数据,相反,它使得没有数据的变量变缺失。
在列输入中加上missover选项时,结果如下:




【关于input的columninput (列输入)和listinput (列表输入).】

我们发现的是,再也没有从下一行读取数据,可是jobcode的pilot和第6行的后面仍然没有正确读入。这是因为在列输入的时候,如果指针到了一行的结尾,仍然没能读入满足变量长度的数值,就会将该变量变缺失。解决方法:可以再加入pad选项,pad选项数据后面填上空格,使得每行的长度相同,默认lrecl=256。

如果列表输入infile加上missover选项,结果如下,不会像列输入那样将最后的变量变缺失。






Truncover: 其实truncover的功能类似于missover 和pad合用的效果,它是针对列输入时,如果一行最后读入的数值仍然不能满足变量需要的长度,不会将变量缺失,而是将读入的值赋给该变量。列输入加truncover的结果同上。
当然,对于列表输入,truncover的结果也同上,是正确的结果。

关于PAD,pad固名思义,意思是将数据行的后面部分填上空格,这样就使得数据行变长,不致于让input指针在读取短数据行时到达数据行结尾从而跳行。Pad不会抑制flowover的作用,它会将数据后面的空白位置填上空格,空格的长度由lrecl=n决定,默认n为256,当然可以在infile选项中修改n的大小。这就是为什么在列输入中用missover和pad可以正确读取数据了,因为数据行的长度不再是数据实际的长度(可变长度),而是一个固定长度256,后面都是空格。
如果列表输入只加pad,不加missover,结果如下




Pad不会抑制flowover,并且将多个空格作为一个处理,所以出现了上述结果。


关于读取外部文件和datalines中的区别,很多朋友都发现sas读取外部文件和datalines数据,数据结构完全一样,同样的程序,结果不同。
原因是:外部文件数据,数据行是可变长度,如上例。除非加上pad,以空格填充。
而在cards中的数据,看起来也是可变长度,但其实是固定长度,为80。结尾没有数据的地方都以空格填充。即默认有pad 。引用davil2000大神的回答:
Cardimagesystem option specifies that SAS source and data lines be processed as if thesewere punched card images—all exactly 80 bytes long and padded with blanks.

所以如下两个程序:
data test3;
input lastn $1-21Firstn $ 22-31
Empid $32-36 Jobcode $37-45;
cards;
LANGKAMMSARAHE0045 Mechanic
TORRESJANE0029 Pilot
SMITHMICHAELE0065
LEISTNERCOLINE0116 Mechanic
TOMASHARALD
WADEKIRSTENE0126 Pilot
WAUGHTIME0204 Pilot
;
run;
data test4;
input lastn Firstn
Empid Jobcode ;
cards;
LANGKAMMSARAHE0045 Mechanic
TORRESJANE0029 Pilot
SMITHMICHAELE0065
LEISTNERCOLINE0116 Mechanic
TOMASHARALD
WADEKIRSTENE0126 Pilot
WAUGHTIME0204 Pilot
;
run;

列输入可以正确读入,列表输入不行,因为没有missover选项,类同于读取外部文件时只加pad选项。

    推荐阅读