认识世界的第一步是正确命名各种实体,在SAS 程序中,标识符是就是用于命名编程语言实体的名称。常用的标识符分为变量名和成员名两大类,包括常量名、变量名、数组名、函数名、逻辑库和文件引用名称,成员和数据集名称等等。标识符名称只能以字母或下划线开头,由字母、下划线或者数字组成。大部分标识符名称(比如数据集名和变量名)遵循长度不得超过32字节规则,除了:
1. 逻辑库引用/文件引用(libref/fileref)名称最长为8字节
2. 函数/调用例程(Function/CALL Routines)函数名最长为16字节
另外,关于长度限制还有如下一些特例:
- 格式名长度限制:字符/数值型输出格式名称最长为31/32字节;字符/数值型输入格式名称最长为30/31字节。
- 数据集描述标签最长为32字节,而数据列描述标签最长为256字节。
在下面的例子中,libref 标识符最长只能 8 个字节。而数据集(表)和变量(列)最长为 32个字节。如果你增加一个字符则会报编译错。
libname lib45678 "c:\temp"; /*逻辑库名最长8字节*/
data lib45678.tab45678901234567890123456789012;/*数据集名最长 32 */
col45678901234567890123456789012=10; /*数据列(变量名)最长 32 */
a_=10;
_a=10;
run;
在下面的例子中,fileref 标识符最长只能8个字符。样例代码演示了在如何将文本写入外部文件 c:\test.log。
/*fileref 最长只能8字节*/
filename file5678 'c:\test.log' encoding="utf-8";
data _null_;
file file5678;
put "Hello World!";
run;
SAS 有两个系统选项可用于控制变量名和成员名的命名规则:
- VALIDVARNAME:指定SAS会话中可以创建和处理的有效的SAS变量名,有三个参数可选:V7 | UPCASE | ANY,默认值为上面讲到的传统命名规则 V7;UPCASE就是在V7命名规则之上,变量名还必须是大写的(用于早期SAS版本);如果变量命名中要包含国家语言字符(如中文),必须指定为 ANY。用法如下:
options validvarname=ANY;
即使启用了 ANY 变量命名规则,变量名仍然不能与系统自动变量 _N_、_ERROR_ 或者系统变量列表 _NUMERIC_、_CHARACTER_ 和 _ALL_ 相冲突。
- VALIDMEMNAME:指定有效的SAS成员名,成员包括SAS数据集、SAS 数据视图、SAS目录、SAS索引及 SAS Item stores 等。有2个参数可选:COMPATIBLE | EXTEND,默认值为 COMPATIBLE;如果成员命名中要包含国家语言字符(如中文)或除了 / \ * ? " < > | : - 之外的特殊字符,必须指定为 EXTEND。用法如下:
options validmemname=EXTEND;
如果启用了这种扩展的命名规则,我们就可以在 SAS 里使用非英文的标识符来命名数据集或者数据集中的变量(即列名)。另外即使启用了EXTEND成员命名规则,命名仍然不得以英文句号开头;对于SPDE引擎,其名则不得包含英文句号且不能以美元符 $ 开头。简单例子如下:
/*逻辑库名最长8字节*/
libname lib45678 "c:\temp";
/*需要 options validmemname=extend; 否则编译错*/
data lib45678."中央人民政府数据库"n;
/*需要 options validvarname=any; 否则编译错*/
"中央人民政府变量名"n=10;
run;
proc contents;run;
你可以在 SAS 中使用如下语句查询特定系统选项的设置:
proc options option=(validvarname validmemname);
run;
常量与变量
在 SAS 语言DATA步中,可以在表达式中直接定义一个数值型或字符型常量。比如:
- 数值型:255,3.1415926,1.25E-10
- 字符型:'Hello World',"HELLO WORLD","张三"
SAS 数值型变量和字符型变量默认长度都是8个字节,其中数值型变量可指定任何 3-8 字节之间的任何长度(Linux/Windows最小长度为3,而不常见的IBM z/OS 平台上最小为2字节),而字符型则可指定 1-32767 字节的任何长度。变量的类型和长度在SAS中可以使用下面三种方式之一显式指定:LENGTH 语句,ATTRIB 语句或者 FORMAT 语句(仅对字符型未指定长度时有效);其中 ATTRIB语句可以同时为多个变量指定类型和长度,而FORMAT则在指定类型和长度时也指定了输出格式信息。比如:
data MyData;
/*数值型 2-8*/
length n1 8;
attrib n2 length=8;
format n3 8.;
/*字符型 1-32767*/
length c1 $ 8;
attrib c2 length=$8;
format c3 $8.;
run;
proc contents;run;
SAS作为一种数据处理语言,需要经常处理没有观测到的数值,称为缺失值。数值型缺失值用单个小数点符号 . 表示,字符型缺失值使用单个空格字符 表示。
data _null_;
missingnum=.; *指定数值型缺失值;
missingstr=' '; *指定字符型缺失值;
call missing(missingnum, missingstr);
*使用 CALL MISSING 例程来将变量设置为缺失值;
nullstr=""; *对于字符型变量,传统的空字符也被当作缺失值看待;
length dotstr $ 1; *对于字符型变量,赋给 . 等价于赋给 ".";
dotstr=.; dotstr2='.';
if dotstr=dotstr2 then put "dotstr is equal to dotstr2";
*检测变量是否为缺失值;
if missingnum=. then put "missingnum is missing";
if missingstr=' ' then put "missingstr is missing";
if nullstr=' ' then put "** nullstr is missing";
*使用函数来检查缺失值;
if missing(missingnum) then put "missingnum is missing";
if missing(missingstr) then put "missingstr is missing";
if missing(dotstr) then put "dotstr is missing";
run;
系统输出:
dotstr is equal to dotstr2
missingnum is missing
missingstr is missing
** nullstr is missing
missingnum is missing
missingstr is missing
数值常量
- 整数与双精度浮点数
数值型常量可以用整数、定点实数以及科学计数法实数表示。但在常量赋给某个变量的时候需要注意精度问题。默认情况下,没有精度丢失的最小和最大整数区间为十六位的整数:-9007199254740992 到9007199254740992(十六进制:FFE0000000000000 – 20000000000000),超过此范围的整数赋值可能精度丢失。
你可以在机器上运行如下程序,对比不同的结果。
data _null_;
intc_min=-9007199254740992; intc_max= 9007199254740992;
put "Integer Constant: " intc_min 17. " ~ " intc_max 17.;
*区间内的数值;
intc_min2= intc_min + 1; intc_max2= intc_max - 1;
put "Integer Constant: " intc_min2 17. " ~ " intc_max2 17.;
*区间外的数值:精度丢失...;
intc_min2= intc_min - 1; intc_max2= intc_max + 1;
put "Integer Constant: " intc_min2 17. " ~ " intc_max2 17.;
intc_min3=-9007199254740993; intc_max3= 9007199254740993;
put "Integer Constant: " intc_min3 17. " ~ " intc_max3 17.;
*区间外的数值重新回到区间内;
intc_min4= intc_min3+1; intc_max4= intc_max3-1;
put "Integer Constant: " intc_min4 17. " ~ " intc_max4 17.;
run;
系统输出:
Integer Constant: -9007199254740992 ~ 9007199254740992
Integer Constant: -9007199254740991 ~ 9007199254740991
Integer Constant: -9007199254740992 ~ 9007199254740992
Integer Constant: -9007199254740992 ~ 9007199254740992
Integer Constant: -9007199254740991 ~ 9007199254740991
实数常量表达式支持除小数点外的11位有效数字(包括符号位);如果用科学计数法表示(比如 2.22507E-308),除小数点外的整个数字(包括尾数、E、E后面的符号位、指数)的有效位为11位。SAS浮点数的表达范围为:2.22507E-308 到1.797693E308(HEX为000FFFFE2E8159D1 到 7FEFFFFFD7B9609A)。
data _null_;
/*定点实数表示: 结果只支持11位有效数字精度(不包括小数点)*/
x=123456789.012; *结果是 123456789.01;
y=0.12345678912; *结果是 0.1234567891;
put "X=" x " Y=" y ;
/*科学计数法表示:SAS 浮点数最小/最大值,除小数点外最长只能有11位有效数字;*/
double_min= 2.22507E-308;
double_max= 1.797693E308;
put "double: " double_min "~ " double_max ;
double1=double_min / 2000000; *等于0.00001E-309 约等于 0;
double2=double_max + 1.0; *表示超出范围,还是最大的浮点数;
put "double1=" double1 "double2=" double2;
double1= 2.225071E-308; *结果是 2.22507E-308;
double2= 1.7976931E308; *结果是 1.797693E308;
put "double1=" double1 "double2=" double2;
run;
- 日期/时间/日期时间
日期/时间/日期时间类型是一种特殊的数值型,其常量定义采用引号后面加d、t或dt来分别表示(大小写均可)。SAS的日期时间数据定义与别的公司不同。比如:SAS 对 DateTime的定义是从公历1960年1月1日00:00:00开始的秒数。而微软对于 DateTime 的定义则是从公历0001年1月1日00:00:00开始的滴答数(Ticks:一秒钟等于1千万个滴答数)。
下面的例子演示了如何利用日期常量,时间常量以及日期时间常量对变量进行赋值:
data _null_;
d='02JAN1960'D;
t='00:00:01'T;
dt='01JAN1960 00:00:01'dt;
put " d=" d date.;
put " t=" t time.;
put "dt=" dt datetime.;
put "value=" d t dt;
run;
运行上面的代码,结果你会发现变量 d、t和dt 不指定格式时的输出值都等于1,但他们的语义不同:d 是1960年1月2日,t是 00:00:01,而 dt 是1960年1月1日凌晨 00:00:01。
在 SAS 系统中,还可以使用 CONSTANT函数来返回数学常量,比如 PI值, E值, EULER欧拉常数等,但一般不推荐大量重复调用 CONSTANT函数来获得常数给变量赋值。
data _null_;
pi=CONSTANT("PI");
e=CONSTANT("E");
euler=CONSTANT('EULER');
put "PI=" pi;
put "E=" e;
put "EULER=" euler;
small=CONSTANT('SMALL');
big=CONSTANT('BIG');
put "Double:" small "-" big;
run;
其中 SMALL和 BIG 分别返回当前机器上8字节所能表达的最小/最大双精度浮点数,即SAS 所能表示的双精度数范围的最小和最大值:2.22507E-308 和1.797693E308。上面代码的输出为:
PI=3.1415926536
E=2.7182818285
EULER=0.5772156649
Double:2.22507E-308 -1.797693E308
字符常量
字符常量需要使用单引号或者双引号括起来,两者的区别是单引号字符串不会进行宏展开,而双引号中的字符串则会进行宏展开。比如:
data _null_;
c="&sysver";
put "SAS Version is " c;
c2='&sysver';
put "SAS Version is " c2;
run;
输出结果为:
SAS Version is 9.3
SAS Version is &sysver
注意:在 SAS 里,如果变量名字包含空格或者国家语言特定的字符,我们可以使用Name Literal来命名。其形式是一个引号括起来的空格或者国家语言字符的字符串常量,引号后面加上n(大小写皆可)。这种特殊的变量命名通常用于关系数据库的表名/列名、SAS 变量名、语句标签 (需要启用系统选项 VALIDVARNAME=ANY);或者SAS数据集、SAS数据视图和Item Store (需要启用系统选项 VALIDMEMNAME=EXTEND)的命名中,用于和外部系统交互而设计的。
*Name Literal 如果包含空格和国家语言字符,需要启用系统选项VALIDVARNAME=ANY;
*否则会报告语法错误;
options validvarname=ANY;
data _null_;
pi=3.1415926;
c="PI"; c2="pi"n;
put c "=" c2;
"var 1"n = 100;
put "var 1=" "var 1"n;
"变量1"n = 100;
put "变量1=" "变量1"n;
run;
系统输出如下:
PI =3.1415926
var 1=100
变量1=100
结语:任何编程都是从常量和变量开始,构建复杂的程序表达世界。SAS与传统编程语言不同之处在于为数据分析从根上定义了面向分析的数据类型和表达方式,从而注定了SAS编程人员的视角是基于一种更加高级、面向信息的数据表达,而不是传统的基于字节和位操作之上的数据结构和算法体系,尽管SAS依然保留了对字节和位层次的操作能力!