admin 管理员组文章数量: 887609
2024年1月19日发(作者:xml文件样式)
SAS编程技巧手册
修订记录
版本号
1.0
1.1
日期
2009-5-1
主要作者
秦源
初始版本。
补充内容。
版本描述
2010-5-19 秦源
受控范围
序号
1
受控范围
上海宝信软件股份有限公司商务智能软件事业部,以下简称“宝信软件BI部”。
目录
1. 数据处理 ................................................................................................................................... 1
1.1. 时间常量 ....................................................................................................................... 1
1.2. 常用时间格式 ............................................................................................................... 1
1.3. 常用时间函数 ............................................................................................................... 2
1.4. 计算两个日期的间隔INTCK函数 ............................................................................... 2
1.5. 修改数据集属性(名称、标签、变量名、变量标签、变量format) ................... 3
1.6. data步中,若某个字段值固定,使用retain代替赋值。 ....................................... 4
1.7. 将数据集中变量的某种值统一替换为另一种值 ....................................................... 4
1.8. 将字符串中的某些字符替换为其它字符TRANWRD函数 ........................................ 5
1.9. 变换字符串中字符的顺序TRANSLATE函数 .............................................................. 5
1.10. COMPRESS函数用法 ................................................................................................ 5
1.11. 判断字符是否为字母或数字 ................................................................................... 6
1.12. 比较数据集异同PROC COMPARE ............................................................................ 6
1.13. 找出重复出现的记录PROC SUMMARY ................................................................... 8
1.14. 查看data步创建的view的代码 ............................................................................ 9
1.15. 从数据集中获取数据,生成自定义format ......................................................... 10
1.16. 判断两个数字值是否相等要用round函数 ......................................................... 11
1.17. 从右向左查找字符 ................................................................................................. 11
1.18. 排名PROC RANK ..................................................................................................... 11
1.19. 用sum函数代替+、- 符号进行计算 ................................................................... 12
1.20. 取得字符串中分隔符间的字符串SCAN函数 ...................................................... 12
1.21. 将同一变量的多个观测的值分组合并为一个观测值 ......................................... 12
展现 ......................................................................................................................................... 15
2.1. 存储过程中的宏%STPBEGIN、%STPEND .................................................................. 15
2.2. 通过存储过程显示静态页面 ..................................................................................... 16
2.3. 查询条件值多选输出 ................................................................................................. 16
2.4. TABULATE中计算加权平均值 ................................................................................... 17
2.5. PROC REPORT计算示例 ............................................................................................. 18
2.6. 在报表中对单元格根据数值范围动态填色 ............................................................. 20
宏 ............................................................................................................................................. 21
3.1. SAS对宏引用符号&、&&、&&&、&&&&的处理机制 ........................................... 21
效率 ......................................................................................................................................... 22
4.1. 对SAS中的临时大表建立索引 ................................................................................. 22
4.2. 对ODS中的大表在etl过程时创建索引 .................................................................. 22
4.3. 反复使用的大表按当期建立临时表,在后续程序中使用。 ................................. 22
4.4. 反复使用的SAS代码制作一个带参数的宏 ............................................................. 23
4.5. 提高时间相关where条件处理效率 ......................................................................... 23
4.6. DATA步SET数据应使用WHERE代替IF .................................................................. 23
4.7. 大数据量数据集更新数据 ......................................................................................... 24
4.8. 在数据集上创建、删除索引 ..................................................................................... 24
系统 ......................................................................................................................................... 25
2.
3.
4.
5.
5.1. 在SAS程序中调用操作系统命令 ............................................................................. 25
5.2. 删除操作系统文件 ..................................................................................................... 25
5.3. 并行运行批作业 ......................................................................................................... 26
5.4. 命令行下生成带日期时间的文件名 ......................................................................... 26
5.5. 输出SAS库、库成员(数据集、视图、索引、编录等)的详细信息 ................. 27
6. 常见问题 ................................................................................................................................. 29
6.1. 自定义format中文转码问题 .................................................................................... 29
6.2. EG连接超时 ............................................................................................................... 30
6.3. 导入csv文件时最后一列数字变为空 ...................................................................... 30
6.4. 中文字段值异常,导出csv文件数据不正确 .......................................................... 31
6.5. CUBE使用format的限制 .......................................................................................... 31
6.6. ODS输出数据时造成误差 ......................................................................................... 31
6.7. put函数使用自定义format的名称长度问题 ......................................................... 31
6.8. ODS输出为非HTML格式时中文乱码 ..................................................................... 31
附录一 ............................................................................................................................................... 1
说明:本手册中的示例代码都在EG4.1中运行通过,若使用BASE SAS或在STP服务器上运行,显示输出需要加入适当的ODS语句。
1. 数据处理
1.1. 时间常量
在SAS中与时间相关的值都是数字,时间值为距0:00:00的秒数,日期值为距1960-1-1的天数,日期时间值为据1960-1-1:00:00:00的秒数。可以将一个合法的时间型数字直接赋给数字型变量,但往往无法知道确切的数字是多少,可以采用时间常量的格式赋值。
data _null_;
format dt1 datetime20. dt2 datetime20. dt3 datetime20. dt4 datetime20.
date1 yymmdd10. date2 yymmdd10.
time1 time10. time2 time10. time3 time10. ;
dt1 = "22SEP2008 09:08:01"dt; dt2 = "10JAN2005:08:08:08"dt;
dt3 = 0; dt4 = 86470;
date1 = "10JAN2005"d; date2 = 0;
time1 = "08:09:10"t; time2 = 0; time3 = 80;
put dt1= dt2= dt3= dt4= ;
put date1= date2= ;
put time1= time2= time3=;
run;
LOG:
dt1=22SEP2008:09:08:01 dt2=10JAN2005:08:08:08
dt4=02JAN1960:00:01:10
date1=2005-01-10 date2=1960-01-01
time1=8:09:10 time2=0:00:00 time3=0:01:20
dt3=01JAN1960:00:00:00
1.2. 常用时间格式
对时间、日期、日期时间的显示或转换成字符型,使用sas自带的format,可省去不少转换步骤。
data _null_;
date=date();
date1=put(date,yymmdd10.); date2=put(date,yymmdd8.); date3=put(date,yymmdd6.);
date4=put(date,yymmddn8.); *不需要写成compress(put(date,yymmdd10.),'-');
yearmonth=put(date,yymmn6.); *不需要写成substr(compress(put(date,yymmdd10.),'-'),1,6);
year=put(date,year4.);
dt="10JAN2009:08:08:08"dt; dt1=put(dt,datetime20.); dt2=put(dt,is8601dt20.);
dt3=put(dt,NLDATM30.);
time="08:09:10"t;
time1=put(time,time8.);*10点前小时只有1位;
time2=put(time,tod8.); *10点前小时会补0,凑足2位;
put date= date1= date2= date3= date4= yearmonth= year= ;
put dt= dt1= dt2= dt3= ;
put time= time1= time2= ;
run;
LOG:
date=17974 date1=2009-03-18
yearmonth=200903 year=2009
date2=09-03-18 date3=090318 date4=20090318
1 / 31
dt=1547194088 dt1=10JAN2009:08:08:08 dt2=2009-01-10T08:08:08
dt3=2009年01月10日 08时08分08秒
time=29350 time1=8:09:10 time2=08:09:10
1.3. 常用时间函数
常用的时间函数,以下用大写突出显示。
data times;
format date1 yymmdd10. date2 yymmdd10. date3 yymmdd10. datep yymmdd10.
dt1 is8601dt20. dt2 is8601dt20.
timep tod8. time1 tod8. time2 tod8.;
date1=DATE(); *返回当前日期值,同TODAY();
dt1=DATETIME(); *返回当前日期时间值;
time1=TIME(); *返回当前时间值;
dt2=DHMS('02JAN2009'd, 8, 13, 21) ;*根据日期、时、分、秒,返回日期时间值;
date2=MDY(3,21,2009); *根据月、日、年返回日期值;
date3=YYQ(2009,4); *根据年、季,返回此季度第一天的日期值;
time2=HMS(12,5,45 ); *根据时、分、秒,返回时间值;
timep=TIMEPART(dt1); *返回日期时间的日期值;
datep=DATEPART(dt1); *返回日期时间的时间值;
year1=YEAR(date1); *返回日期的年;
qauter1=QTR(date1); *返回日期的季度。;
month1=MONTH(date1); *返回日期的月;
day1=DAY(date1); *返回日期的日;
day2=WEEKDAY(date1); *返回日期的星期几,1~7为星期日~星期六;
hour1=HOUR(dt2); *返回日期时间值或时间值的小时;
minute1=MINUTE(dt2); *返回日期时间值或时间值的分钟;
second1=SECOND(dt2); *返回日期时间值或时间值的秒;
run;
值显示列表:
date1
date2
date3
datep
dt1
dt2
timep
time1
time2
2009-4-17
2009-3-21
2009-10-1
2009-4-17
2009-04-17T15:01:53
2009-01-02T08:13:21
15:01:53
15:01:53
12:05:45
year1
qauter1
month1
day1
day2
hour1
minute1
second1
2009
2
4
17
6
8
13
21
1.4. 计算两个日期的间隔INTCK函数
若要计算两个日期间隔的天数、工作日、周、月、季、年等,可用INTCK函数。
2 / 31
data intervals;
length date1 8 date2 8 type $15 interval 8;
format date1 yymmdd10. date2 yymmdd10.;
retain date1 '02JAN2009'd date2 '25SEP2010'd;
type='day'; interval=INTCK(type,date1,date2);output; *间隔的天数,等于date2-date1;
type='weekday';interval=INTCK(type,date1,date2);output; *间隔的工作日数,排除周六、周日;
type='week'; interval=INTCK(type,date1,date2);output; *间隔的周数;
type='month'; interval=INTCK(type,date1,date2);output; *间隔的月数;
type='qtr'; interval=INTCK(type,date1,date2);output; *间隔的季数;
type='year'; interval=INTCK(type,date1,date2);output; *间隔的年数;
run;
值显示列表:
date1
2009-1-2
2009-1-2
2009-1-2
2009-1-2
2009-1-2
2009-1-2
date2 type interval
631
450
90
20
6
1
2010-9-25 day
2010-9-25 weekday
2010-9-25 week
2010-9-25 month
2010-9-25 qtr
2010-9-25 year
1.5. 修改数据集属性(名称、标签、变量名、变量标签、变量format)
经常有初学者为了修改数据集属性,每次都要新生成一个数据集,写出如下垃圾代码:
*重命名数据集t1为t2;
data t2;
set t1;
run;
*修改数据集标签;
data t1(label='数据集1');
set t1;
run;
*修改变量名、标签、format等;
data t1;
set t1;
var2=var1;
label var3='变量3';
format var4 yymmdd10.;
run;
其实数据本身并没改变,只要改数据集的属性即可,可采用以下代码:
3 / 31
proc datasets library=mylib nolist; *指定库名;
change hightemp=ushigh lowtemp=uslow; *更改数据集名;
modify t1(label='数据集1'); *更改数据集标签;
modify hurricane;
rename State=Place Deaths=USDeaths; *更改变量名;
format Date yymmdd10; *更改变量format;
label Millions='数量' Place='位置'; *更改变量标签;
quit;
1.6. data步中,若某个字段值固定,使用retain代替赋值。
data total1;
do i=1 to 1000000;
id = i;
output;
end;
retain t 't1' c 'c1';
drop i;
run;
以上t、c的值只处理一遍,效率高。
data total1;
do i=1 to 1000000;
id = i;
output;
end;
t='t1';
c='c1';
drop i;
run;
每处理一条记录都要给t、c赋值,效率低。
1.7. 将数据集中变量的某种值统一替换为另一种值
例:将数据集中所有数字型变量的空值.替换为0,可采用以下代码,不需要写多个if语句。以下代码中:array alln _numeric_表示定义一个数组,所有数字型变量为成员(若要使用所有字符型变量,用_character_表示)。
data t1;
set t1;
array alln _numeric_;
do over alln;
if alln = . then alln = 0;
end;
run;
若只需要处理某几个字段,可用以下代码:
data fa1;
set fa1;
array all(*) H2O TFe CaO SiO2 ;
do i = 1 to 4;
if all(i)=0 then all(i)=.;
end;
drop i;
run;
4 / 31
1.8. 将字符串中的某些字符替换为其它字符TRANWRD函数
data _null_;
a='aabccdbce';
b=tranwrd(a,'bc','fff');
put a= b=;
run;
LOG:
a=aabccdbce b=aafffcdfffe
1.9. 变换字符串中字符的顺序TRANSLATE函数
data _null_;
a='abcde';
b = translate('13254', a, '12345');
put a= b=;
run;
LOG:
a=abcde b=acbed
1.10. COMPRESS函数用法
语法:compress([字符串][,字符][,修饰符]),其中修饰符不区分大小写。
我们一般只用到了compress(string)、compress(string,'-:_')这两种用法,其实用compress函数去除特定的一些字符时,不需要把所有的字符都列到第二个参数里,而且某些字符是无法通过键盘输入的,可以用第三个参数指定(SAS8不支持)。
修饰符 说明
a
c
d
f
g
i
k
l
n
o
将字母(A - Z, a - z)、中文加入字符列表。
将控制字符加入字符列表。
将数字加入字符列表。
将下划线字符、字母(A - Z, a - z)加入字符列表。
将图表字符加入字符列表。
忽略字符大小写。
保留列表中的字符,而不是删除。
将小写字母(a - z)、中文加入字符列表。
将数字、下划线、字母(A - Z, a - z)加入字符列表。
一次性处理第二、第三个参数,而不是每次调用函数时都处理。
在data步或sql步中(不包括where子句)使用此修饰符,当在循环中调用compress且第二、三参数不变时,会极大加快处理速度。
p
s
t
u
w
x
将标点符号加入字符列表。
将分隔字符加入字符列表。(空格、水平制表符、垂直制表符、回车、换行、换页)
去除第一、二参数的尾部空格。
将大写字母(A - Z)加入字符列表。
将可打印字符加入字符列表。
将十六进制字符加入字符列表。
5 / 31
示例:
data _null_;
s = "中国AAAbABBBc_134@#$,!.";
s1 = compress(s,,'d'); *去除数字;
s2 = compress(s,,'a'); *去除字母、中文;
s3 = compress(compress(s,,'n'),,'kl');*保留中文;
s4 = compress(s,,'p');*去除标点符号;
put s1= s2= s3= s4=;
run;
1.11. 判断字符是否为字母或数字
data _null_;
s='中国+abc*GH390wq#';
s1='+$%^&*';
a1=anyalpha(s); *返回第一个字母字符的位置;
a2=notalpha(s); *返回第一个不是字母字符位置;
a3=anydigit(s); *返回第一个数字字符的位置;
a4=notdigit(s); *返回第一个不是数字字符的位置;
b1=anyalpha(s1);
b2=anydigit(s1);
put a1= a2= a3= a4=;
put b1= b2=;
run;
LOG:
a1=6 a2=1 a3=12 a4=1
b1=0 b2=0
1.12. 比较数据集异同PROC COMPARE
若需要比较2个结构相同的数据集的各变量值的异同,可使用proc compare,十分方便,可以输出详细的比较信息。详细语法请见SAS帮助。
6 / 31
data emp1;
input @1 idnum $4. @6 name $15. @22 address $42. @65 salary 9.;
cards;
2388 James Schmidt 100 Apt. C Blount St. SW Raleigh NC 27693 92100
2457 Fred Williams 99 West Lane Garner NC 27509 33190
2776 Robert Jones 12988 Wellington Farms Ave. Cary NC 27512 29025
8699 Jerry Capalleti 222 West L St. Oxford NC 27587 39985
2100 Lanny Engles 293 Manning Pl. Raleigh NC 27606 30998
9857 Kathy Krupski 1000 Taft Ave. Morrisville NC 27508 38756
0987 Dolly Lunford 2344 Persimmons Branch Apex NC 27505 44010
3286 Hoa Nguyen 2818 Long St. Cary NC 27513 87734
6579 Bryan Samosky 3887 Charles Ave. Garner NC 27508 50234
3888 Kim Siu 5662 Magnolia Blvd Southeast Cary NC 27513 77558
;
data emp2;
input @1 idnum $4. @6 name $15. @22 address $42. @65 salary 9.;
cards;
2388 James Schmidt 100 Apt. C Blount St. SW Raleigh NC 27693 92100
2457 Fred Williams 99 West Lane Garner NC 27509 33190
2776 Robert Jones 12988 Wellington Farms Ave. Cary NC 27511 29025
8699 Jerry Capalleti 222 West L St. Oxford NC 27587 39985
3278 Mary Cravens 211 N. Cypress St. Cary NC 27512 35362
2100 Lanny Engles 293 Manning Pl. Raleigh NC 27606 30998
9857 Kathy Krupski 100 Taft Ave. Morrisville NC 27508 40456
0987 Dolly Lunford 2344 Persimmons Branch Trail Apex NC 27505 45110
3286 Hoa Nguyen 2818 Long St. Cary NC 27513 89834
6579 Bryan Samosky 3887 Charles Ave. Garner NC 27508 50234
3888 Kim Siu 5662 Magnolia Blvd Southwest Cary NC 27513 79958
;
run;
/*先要对2个数据集按id排序,再按id比较数据集其它变量的值,若不指定id,则按观测号顺序比较,指定out=,将数据输出到数据集result,不指定则输出报表。*/
proc sort data=emp1;
by idnum;
run;
proc sort data=emp2;
by idnum;
run;
proc compare base=emp1 comp=emp2 brief;
id idnum;
run;
proc compare base=emp1 comp=emp2 out=result outnoequal outbase outcomp outdif noprint;
id idnum;
run;
proc print data=result label noobs;
by idnum;
id idnum;
run;
显示结果:
7 / 31
导出的数据集result中,BASE表示proc compare中base=指定的数据集数据,COMPARE表示comp=指定的数据集,DIF表示差异,“.”表示同样位置的字符相同,X表示同样位置的字符不同,数字型的值相等的话用E表示,不等则为COMPARE值-BASE值。
1.13. 找出重复出现的记录PROC SUMMARY
生成示例数据集
8 / 31
%let totalSize = 5000000;
%let DupRate = 0.8;
data total;
array v(*) v1 - v5;
do i=1 to &totalSize;
do j=1 to dim(v);
v(j) = 100 + 2 - rantbl(-1, (1 - &DupRate ));
end;
output;
end;
drop i j;
run;
方法一,性能较高
proc summary data=total nway;
class v1 - v5;
output out=out2(drop=_type_ where=(_freq_>1)); *_freq_值表示出现的频数;
run;
方法二,性能较低
proc sql;
create table out3 as
select * ,count(v1) as freq
from total
group by v1,v2,v3,v4,v5
having count(v1)>1;
quit;
1.14. 查看已创建的view的代码
*data步创建示例view;
data male /view=male;
set ;
where sex='M';
run;
*查看view代码;
data view=male;
describe;
run;
*sql步创建示例view;
proc sql;
create view sv as
select * from where sex='F';
quit;
*查看view代码;
proc sql;
describe view sv;
quit;
data步、sql步创建的view要用对应的方法查看。如:若用data步方法查看sql步创建的view,
9 / 31
则出错ERROR:
视图
被损坏或不是 DATA
步视图。反之亦然。
1.15. 从数据集中获取数据,生成自定义format
大部分情况下,自定义format中的值不能固定写死,需要从某些对照表中取得,可以直接使用以下宏,指定来源表、值变量名、显示格式值变量名即可。
%macro fmt(tb=,sta=,lab=,fmt=,lib=library);
data &fmt(drop=&sta &lab);
attrib start length=$50.;
attrib label length=$100.;
set &tb(keep=&sta &lab);
start=compress(&sta);
label=trim(left(substr(&lab,1,100)));
run;
*去掉重复值;
proc sort data=&fmt nodupkey;
by start;
quit;
*生成符合要求格式的表,start为值,label为值对应的显示值;
data &fmt;
set &fmt end=last;
retain fmtname "&fmt" type 'c' HLO '' min 1 max 100 default 100 length 100;
output;
if last then do;
start='N/A';
label='N/A';
hlo='O';
output;
end;
run;
*生成format;
proc format library=&lib cntlin=&fmt;
quit;
proc datasets lib=work nolist;
delete &fmt;
quit;
%mend fmt;
*工号-姓名;
%fmt(tb=_USER, sta=USER_ID, lab=USER_NAME, fmt=wp_wkno)
注意:自定义format在SAS中的存放路径为[libname].[catalog]([库名].[编录名]),若不指定存放的库名,默认为work;若不指定编录名,默认为formats;即默认情况下自定义format是存放在s中的。但work中的format在进程结束后会消失,若想永久使用则需要指定库名存放到其它库中。若存放自定义format的库不是work或library,或者不是默认的编录名,在使用之前需要执行类似以下语句,系统才能正确找到format。
options FMTSEARCH=(work t library custlib t);
library是一个特殊的库,在服务器的配置文件里都已默认设置了路径,所以可以直接使用,其它的库必须在程序中运行libname语句分配或修改配置文件。
10 / 31
1.16. 判断两个数字值是否相等要用round函数
在SAS中看起来相等的两个数字值直接比较,往往会认为不相等。
data _null_;
x=3.3;
y=1.1*3;
put x= y=;
if x=y then put 'x equal y';
else put 'x not equal y';
if round(x-y,0.00001)=0 then put 'x=y';
else put 'x<>y';
run;
LOG:
x=3.3 y=3.3
x not equal y
x=y
主要是因为计算机二进制计算小数再转换为十进制,与我们直接十进制计算小数会有一点差异,所以判断两个值是否相等不能用
if a=b then ... ,很可能会判断为不等,应改为
if round(a-b, 0.0001)=0 then ... (精度可根据具体情况调整)
1.17. 从右向左查找字符
用index函数可以查找某个字符的位置,但系统是从左向右查找的,返回第一次出现的位置,若想从右向左查第一次出现的位置,可用find函数。
data _null_;
str1='/dw/mart_wp/XTGL/SPZCCB000101';
pos=find(str1,'/',-length(str1));
str2=substr(str1,1+pos);
put pos= str2=;
run;
LOG:
pos=17 str2=SPZCCB000101
1.18. 排名PROC RANK
使用proc rank,可以方便的按数据集中任意字段值对数据进行排名,根据处理好的名次可以做进一步的后续处理。
11 / 31
data elect;
input Candidate $ 1-11 District 13 Vote 15-18 Years 20;
datalines;
Cardella 1 1689 8
Latham 1 1005 2
Smith 1 1406 0
Walker 1 846 0
Hinkley 2 912 0
Kreitemeyer 2 1198 0
Lundell 2 2447 6
Thrash 2 912 2
;
run;
proc rank data=elect out=results ties=low descending;/*倒排序*/
by district;/*按地区分组排名*/
var vote years;/*进行排名的变量*/
ranks VoteRank YearsRank;/*新生成的名次变量*/
run;
Results数据集内容:
1.19. 用sum函数代替+、- 符号进行计算
多个变量进行加、减计算时,如果直接用+、-符号计算,如total=var1+var2-var3-var4,只要有一个变量值为空,则计算值total就为空,但其实我们希望能有值的。为了防止上述情况出现,代码中把+、-都改为使用sum函数,如total=sum(var1,var2,-var3,-var4)。
1.20. 取得字符串中分隔符间的字符串SCAN函数
scan函数中指定分隔符字符,分隔符分隔的第几个字符串,即可方便的得到结果。若不指定分隔符,SAS默认分隔符为:< ( + & ! $ * ) ; ^ - / , % |
data test;
str1='/dw@mart_wp/XTGL*SPZCCB000101';
a=scan(str1,3,'/@*');
run;
结果
1.21. 将同一变量的多个观测的值分组合并为一个观测值
示例:以下数据中同一个供应商代码有多条记录,需要合并成一条,多个物料代码中间用逗号隔开,数量、金额累加。
12 / 31
/*原始数据*/
data test1;
attrib supplier_id length=$8 label='供应商代码';
attrib item_id length=$15 label='物料代码';
attrib qty length=8 label='数量';
attrib amount length=8 label='金额';
input supplier_id $ item_id $ qty amount;
datalines;
911485 A1632166 16.553 11986.01636
914749 A1632121 22.171 11581.32707
914785 A1927892 31.2382 15614.37556
914785 A1927892 29.2299 14643.61666
901190 A1632155 16.7994 8750.595129
911485 A1632166 16.897 12210.20367
911485 A1632166 18.2487 13233.57959
914749 A1632121 14.5189 7625.659441
914749 A1632121 14.5198 7645.516735
914751 A1686914 10.0676 5670.200188
914751 A1686918 5.8662 4927.997534
914785 A1927876 . 6105.317697
914785 A1927886 8.4165 .
914785 A1927886 9.7737 4866.367357
914785 A1927886 17.4209 6670.834309
009934 A1927892 5.8825 2941.25
;
run;
proc sort data=test1;
by supplier_id item_id;
run;
原始数据
合并处理
13 / 31
/*按供应商代码汇总数量、金额,并将多个物料代码合并为一条,中间用逗号隔开*/
data combines(drop=temp_item_id temp_amount temp_qty item_id);
set test1;
by supplier_id item_id;
attrib temp_item_id length=$100;/*合并的变量长度要足够大,否则会截断字符*/
attrib temp_amount length=8;
attrib temp_qty length=8;
attrib ITEM_ID_ALL length=$100;
retain temp_item_id temp_qty temp_amount;
if er_id then do;
temp_item_id=item_id;
temp_qty=qty;
temp_amount=amount;
if er_id then do;
ITEM_ID_ALL=compress(temp_item_id);
output;
end;
end;
else do;
temp_qty+qty; /*这种写法遇到空值作为0处理,效果同tmep_qyt=sum(temp_qty,qty)*/
temp_amount+amount;
if index(temp_item_id,item_id)<1 then
temp_item_id=compress(temp_item_id)||","||compress(item_id);
if er_id then do;
ITEM_ID_ALL=compress(temp_item_id);
qty=temp_qty;
amount=temp_amount;
output;
end;
end;
run;
结果:
1.22. 转置数据PROC TRANSPOSE
可以将数据集行列进行转换,以下列出常见的用法,其它详见SAS帮助。
14 / 31
/*示例数据*/
data testdata;
attrib s_num length=$20 label='材料号';
attrib order_no length=$20 label='订单号';
attrib order_amount length=8 label='订单量';
input s_num $ order_no $ order_amount;
datalines;
A1 ORDER1 10
A1 ORDER2 3
A2 ORDER2 18
A2 ORDER3 52
A2 ORDER4 7
A3 ORDER1 90
A3 ORDER4 28
;
run;
/*按材料号分组,将各个订单号转换为一条记录的不同字段的值*/
proc transpose data=testdata out=temp01(drop=_NAME_ _LABEL_);
by s_num;
var order_no;
run;
/*按材料号分组,将各个订单号转换为字段名,订单量转换为对应订单号字段的值*/
proc transpose data=testdata out=temp02(drop=_NAME_ _LABEL_);
by s_num;
id order_no;
run;
1.23. 导入外部数据时指定起始行
导入外部数据如csv文件时,默认从第二行开始导入,可设置参数指定导入开始行,详见SAS帮助。
proc import datafile="/temp/" out=mydata dbms=csv replace;
datarows=3;
run;
2. 展现
2.1. 存储过程中的宏%STPBEGIN、%STPEND
存储过程中的%STPBEGIN、%STPEND为生成和递交输出提供了标准化的功能,这可以最小化编写生成不同格式、样式内容的存储过程时的编程工作。不使用ODS输出的存储过程,不要使用这些宏,如:在data _null_中put HTML代码的方式或使用ods html的方式输出报
15 / 31
表,则不能写%STPBEGIN %STPEND,否则会出错。
2.2. 通过存储过程显示静态页面
对于静态报表,即定时生成的HTML文件,若直接通过web路径访问,权限很难控制,很不安全,可通过存储过程显示已生成好的页面,对存储过程授权。
%global fname yearmonth fullname;
*假设静态文件路径为/dw/prog/mart_wp/rphtml/报表编号/报表编号_;
data _null_;
call symput('fullname',"/dw/prog/mart_wp/rphtml/&fname/&fname._&yearmonth..html");
run;
data _null_;
*若文件不存在,则指向提示文件;
if FILEEXIST("&fullname")=0 then
call symput('fullname',"/dw/prog/mart_wp/rphtml/");
run;
*显示静态页面;
data _null_;
infile "&fullname";
input;
file _webout;
put _infile_;
run;
注意:不能使用%STPBEGIN、%STPEND
2.3. 查询条件值多选输出
例:查询页面中有一多选控件cbox,如果选择了多个值,传给存储过程时,SAS会自动为每个值产生一个宏,名称以cbox开头,从1开始依次编号,同时产生一个宏cbox0,值为选择值的个数。若只有单选,则只有cbox,不会产生其它宏。
16 / 31
%global cbox cbox0;
%let condition=;
%let cboxs="&cbox";
%macro getdata;
%if &cbox ne all %then %do;
%if &cbox0 ne %then %do;
%do i=2 %to &cbox0;
%let cboxs=&cboxs,"&&cbox&i";
%end;
%end;
%let condition=where region in (&cboxs);
%end;
data temp;
set ;
&condition;
run;
%mend;
%getdata;
……
2.4. TABULATE中计算加权平均值
例:假设某些物料的采购单价分别为m1、m2、„„、mn=,采购数量分别为t1、t2、„„、tn,则计算物料的平均单价的一般方法为 总金额/总量,先把每个物料的金额算出来,再汇总除以总量,需要单独计算。
但在tabulate中可以直接使用weight参数指明权重,自动计算加权平均值,即指定weight=t,则相当于计算(m1*t1+m2*t2+...+mn*tn)/(t1+t2+...+tn),若不指定weight,则计算简单平均。
data tmp1;
input currdate item_type $ item_id $ w t @@;
informat currdate yymmdd10.;
format currdate yymmdd10. w best32. t best32.;
datalines;
2006-07-01 类型一 010001 100 2 2006-07-01 类型一 010002 60 1
2006-07-01 类型一 010003 120 3 2006-07-01 类型二 020001 150 3
2006-07-01 类型二 020003 180 2 2006-07-01 类型二 020004 100 2
2006-07-02 类型一 010001 120 2 2006-07-02 类型一 010002 70 1
2006-07-02 类型一 010003 150 3 2006-07-02 类型二 020001 180 3
2006-07-02 类型二 020003 110 2 2006-07-02 类型二 020004 90 2
;
run;
PROC TABULATE DATA=tmp1 order=data;
CLASS item_type item_id currdate;
VAR t;
var m /weight=t;
TABLE (item_type=''*(item_id='' all='小计')) all='总计' ,
(currdate='' all='合计') *m='' *mean=''
/BOX={label='类型 / 物料'};
RUN;
17 / 31
2.5. PROC REPORT计算示例
在PROC REPORT中可以灵活的做各种计算并定义显示格式等。
1. 示例数据集和自定义格式。
data grocery;
label Sector='区域' Manager='经理' Department='部门' Sales='销售额';
input Sector $ Manager $ Department $ Sales @@;
datalines;
se 1 np1 50 se 1 p1 100 se 1 np2 120 se 1 p2 80
se 2 np1 40 se 2 p1 300 se 2 np2 220 se 2 p2 70
nw 3 np1 60 nw 3 p1 600 nw 3 np2 420 nw 3 p2 30
nw 4 np1 45 nw 4 p1 250 nw 4 np2 230 nw 4 p2 73
nw 9 np1 45 nw 9 p1 205 nw 9 np2 420 nw 9 p2 76
sw 5 np1 53 sw 5 p1 130 sw 5 np2 120 sw 5 p2 50
sw 6 np1 40 sw 6 p1 350 sw 6 np2 225 sw 6 p2 80
ne 7 np1 90 ne 7 p1 190 ne 7 np2 420 ne 7 p2 86
ne 8 np1 200 ne 8 p1 300 ne 8 np2 420 ne 8 p2 125
;
run;
proc format;
value $sctrfmt 'se' = '东南'
'ne' = '东北'
'nw' = '西北'
'sw' = '西南';
value $mgrfmt '1' = 'Smith' '2' = 'Jones'
'3' = 'Reveiz' '4' = 'Brown'
'5' = 'Taylor' '6' = 'Adams'
'7' = 'Alomar' '8' = 'Andrews'
'9' = 'Pelfrey';
value $deptfmt 'np1' = '纸类'
'np2' = '罐头'
'p1' = '肉类/乳制品'
'p2' = '农产品';
run;
2. PROC REPORT计算利润、占区域比例及总比例并输出报表。
18 / 31
proc report data=grocery;
column sector department sales Profit sctrpct sales=salespct;
define sector / group format=$sctrfmt.;
define department / group format=$deptfmt.;
define sales / analysis sum format=dollar9.2;
define profit /'利润' computed format=dollar9.2;
define sctrpct /'区域比例' computed format=percent9.2 ;
define salespct /'总比例' pctsum format=percent9.2;
compute profit; *计算利润;
if department='np1' or department='np2'
then profit=0.4*;
else profit=0.25*;
endcomp;
compute before sector;
sctrtot=; *计算sector总的sales量;
sctrpct=/sctrtot;
endcomp;
compute sctrpct;
sctrpct=/sctrtot; *计算department的sales量;
endcomp;
break after sector / summarize;
compute after sector;
sector='';
department='小计';
call define(_row_,'style','Style=[background=yellow]'); *黄色突出显示小计行;
endcomp;
rbreak after / summarize;
compute after;
sector='合计';
sctrpct=.;
call define(_row_,'style','Style=[background=#80FF80]'); *浅绿色突出显示合计行;
endcomp;
where sector contains 'n';
title '南方区域销售报告';
run;
3. 输出结果:
19 / 31
2.6. 在报表中对单元格根据数值范围动态填色
某些情况下,需要根据报表数值用不同颜色突出显示数据,可用自定义format实现。
/*创建示例数据集 */
data ddt;
input x y;
cards;
1 25
2 30
3 40
4 50
5 55
7 60
6 90
;
run;
/*计算统计量*/
proc means data=ddt noprint;
var y;
output out=outddt;
run;
data _null_;
set outddt;
if _stat_='MIN' then call symput('MIN1',y);
if _stat_='MEAN' then call symput('MEAN1',y);
if _stat_='MAX' then call symput('MAX1',y);
run;
20 / 31
/*创建自定义颜色格式,
值<=MIN1为蓝色,MIN1<值<=MEAN1为粉红色,MEAN1<值 proc format; value tlight low - &MIN1='Blue' &MIN1 - &MEAN1='Pink' &MEAN1 - <&MAX1='Green' &MAX1 - high='Red'; run; /*输出结果*/ proc report data=ddt nowd headline; column X Y; define X / display 'x-label' style(column)=[foreground=black background=white]; define Y / analysis 'y-label' style(column)=[foreground=white background=tlight.]; run; 显示结果: 3. 宏 3.1. SAS对宏引用符号&、&&、&&&、&&&&的处理机制 SAS中通过&name引用一个宏变量name的值,但在实际编程中经常碰到诸如&&name&i甚至&&&的情况,初学者很容易被其迷惑,不过在了解SAS宏处理机制后,这个问题不难理解。例: 宏变量名 i location name1 name 宏变量值 1 beijing shanghai location SAS宏处理器在读到SAS代码中的&时,会: 1、 向后继续读一个字符; 2、 如果后面的字符也为&,则宏处理器将读到的两个&&并做一个&看待,然后转到步骤1; 3、 否则,将后面连续的非&字符(直到空格或&)做为宏变量名字符串。 21 / 31 对于&&name&i,解析流程如下: &&name&i ——> (&&)name(&i) ——> &name1 ——> shanghai 对于&&&name,解析流程为: &&&name ——> (&&)(&name) ——> &location ——> beijing 对于&&&&name,解析流程为: &&&&name ——> (&&)(&&)name ——> &&name ——> (&&)name ——> &name ——> location 3.2. 常用自动宏变量 SAS中有一些自动宏变量,由系统自动赋值,可以直接使用。 宏变量名 SYSDATE SYSDATE9 SYSDAY SYSTIME SYSUSERID SYSJOBID 系统日期,2位年 系统日期,4位年 系统星期 系统时间 执行SAS进程的系统账号 系统进程ID 上一个SQL步执行的记录数,只有SQL步才会改变值,DATA步不会改变值。 若有表生成或有显示输出,则sqlobs值为表的记录数或显示SQLOBS 的记录数(不需要再使用select count(*) into:xxx来获得上一步生成的表的记录数); 若不生成表且设置了noprint,记录数不为0的情况下,sqlobs值为1 SYSLAST 最近一次创建的表名 1 12 说明 值举例 24FEB11 24FEB2011 Thursday 03:33 qysrv 1781942 注意:以上宏变量值在进程启动后赋值,执行过程中值不会自动改变。 执行 %put _automatic_; 可查看所有系统相关的宏变量。 4. 效率 4.1. 对SAS中的临时大表建立索引 程序中反复使用到的临时大表,可对后续处理中的where条件、join连接等主要字段建索引,以加快处理速度。 4.2. 对ODS中的大表在etl过程时创建索引 主要针对etl2程序中处理ODS表时用到的where条件、join连接等字段建立索引。抽取数据量较大的话,要先删除索引再加载数据,完成后再重建索引,否则加载速度会很慢。 4.3. 反复使用的大表按当期建立临时表,在后续程序中使用。 多个主题可能用到同样的源表,如果抽取条件相同的话,没有必要在每个主题程序中重复抽取相同的数据,可以先建立一个临时表,后续程序中直接使用,以节省反复抽取的时间。 22 / 31 4.4. 反复使用的SAS代码制作一个带参数的宏 通用的、反复使用的代码,不要在每个程序中写死,写成带参数的宏放在头文件里,各个程序中引用。 4.5. 提高时间相关where条件处理效率 取数据时,经常需要根据时间字段值取最近一段时间的数据,如: data t1; set mydata; where put(datepart(CREATION_TIME),yymmn6.)>=put(intnx('month',today(),-1),yymmn6.); run; 以上代码是要取mydata中CREATION_TIME(创建时间)为最近一个月的数据,put多此一举,可以改为: data t1; set mydata; where datepart(CREATION_TIME) >= intnx('month',today(),-1); run; intnx('month',today(),-1)的值在代码运行时是固定的,但每次判断时都要执行一遍,可进一步提高效率,改为: data _null_; call symput('baseline', intnx('month',today(),-1)); run; data t1; set mydata; where datepart(CREATION_DATE) >= &baseline; run; 若where语句中有多个条件,要把数据范围小的条件放在前面,可提高效率。如以下代码:假设每天都有很多FLAG='1'记录,若这个条件放在最前面,效率会很低。 data t1; set mydata; where CREATE_DATE eq date() and FLAG='1'; run; 4.6. DATA步SET数据应使用WHERE代替IF 执行如下代码 data t1; set mydata; if datepart(CREATION_DATE) >= &baseline; run; 在DATA步中SET数据时若使用IF筛选数据,系统处理时是SET所有的数据,然后再删除不满足IF条件的数据。而使用WHERE语句,系统只SET满足条件的数据,数据量大时可大大提高效率。 23 / 31 data t1; set mydata; where datepart(CREATION_DATE) >= &baseline; run; 4.7. 大数据量数据集更新数据 若数据集记录数达到百万、千万级,使用SQL步update数据会很慢,例如: proc sql; update dataset1 set field1 = catt('BGLJ',substr(field1,5)) where field1 like 'BSTP%'; update dataset1 set field1 = catt('BGYY',substr(field1,5)) where field1 like 'BGSG%'; quit; 可以改成DATA步处理,速度会较快,但整个表会重建。 data dataset1; set dataset1; if substr(field1,1,4) eq 'BSTP' then field1 = catt('BGLJ',substr(field1,5)); else if substr(field1,1,4) eq 'BGSG' then field1 = catt('BGYY',substr(field1,5)); run; 4.8. 在数据集上创建、删除索引 对记录超过10000条以上的表的查询、连接原则上要在表上建索引,以提高速度。 创建索引的方法如下: 方法一 data (index=(column1 column2 index1=(column1 column3))); /*„„*/ run; 说明:此方法在data步创建表的同时创建索引,一共创建了三个索引,单个字段column1、column2的索引为简单索引,索引名同字段名,多个字段column1、column3组合成的索引为复合索引,可自定义索引名index1。 方法二 proc datasets lib=mylib nolist; modify mydata; index create column1 column2 index1=(column1 column3); quit; 说明:此方法对已存在的数据集创建索引。 方法三 proc sql; create index column1 on (column1); create index column2 on (column2); create index index1 on (column1 column3); quit; 说明:使用sql步创建索引。 24 / 31 删除索引方法: 方法一 proc datasets lib=mylib nolist; modify mydata; index delete column1 column2 index1; quit; 方法二 proc sql; drop index column1 on ; drop index column2 on ; drop index index1 on ; quit; 注意事项: 1. 若字段的唯一值不多,大部分都是重复的值,则对这些字段建索引没有意义,无法提高效率。 2. 对于在建有索引表的添加(append)删除(delete)操作要分别对待:如果要删除或添加数据较少,可直接在建有索引的表上操作;如果记录较多,则需要先删除索引,接着进行append 或delete操作,然后再重建索引,否则系统在操作过程中会不断自动重建索引,速度会非常慢。 3. 查询、连接、删除等操作要使用建索引的相应字段,并且字段上不能使用函数,否则索引不起作用。如:使用了compress(column1)等字符串处理函数。 5. 系统 5.1. 在SAS程序中调用操作系统命令 某些情况下,需要在SAS程序中调用操作系统的命令,可采用如下三种方法。 *方法一,使用X声明; x "dir c: >c:"; *方法二,使用call system例程; data _null_; call system("dir c: >c:"); run; *方法三,使用系统宏,注意不能有引号; %sysexec dir c: >c:; 5.2. 删除操作系统文件 在SAS程序中删除操作系统中的文件,可用如下代码: 25 / 31 %MACRO delFile(fname); filename myfile "&fname"; *检查文件是否存在; %IF %sysfunc(fexist(myfile)) %THEN %DO; options noxwait noxsync xmin; data _null_; x del "&fname"; run; *检查文件是否被删除; %IF %sysfunc(fexist(myfile)) %THEN %put **** Error Occurred *****; %ELSE %put **** Successfully *****; %END;%ELSE %DO; %put **** File Not Exist ****; %END; filename myfile clear; %MEND; %delFile(c:); 5.3. 并行运行批作业 一般运行批作业是通过操作系统定时运行shell程序实现的(Windows下为*.bat或*.cmd,UNIX下为*.sh),在shell程序中可执行各种可执行文件调用相应的程序(如*.sql、*.sas等)。正常情况下都是按顺序一行一行执行的,前面的执行完毕才能执行后面的,若想并行运行多个作业,则可按如下方法实现,作业都在后台运行,不影响其它后续调用。 UNIX系统,在作业命令最后加上& logdir=/dw/saslog/mart_wp batchdir=/dw/prog/mart_wp/script/sql sas -sysin $batchdir/ -dmsbatch -noterminal -noprint -log $logdir/ & sas -sysin $batchdir/ -dmsbatch -noterminal -noprint -log $logdir/ & sas -sysin $batchdir/ -dmsbatch -noterminal -noprint -log $logdir/ & Windows系统,使用start调用作业命令 set logdir=d:dwsaslogmart_wp set batchdir=d:dwprogmart_wpscriptsql start -sysin "%batchdir%" -nosplash -noicon -noprint -log "%logdir%" start -sysin "%batchdir%" -nosplash -noicon -noprint -log "%logdir%" start -sysin "%batchdir%" -nosplash -noicon -noprint -log "%logdir%" 5.4. 命令行下生成带日期时间的文件名 生成日志文件时,一般希望文件名中带上日期时间,以便保存查看,可用如下方法。 UNIX系统 26 / 31 logdir=/dw/saslog/mart_wp batchdir=/dw/prog/mart_wp/script/sql curtime=`date +%Y%m%d_%H%M` sas -sysin $batchdir/ -dmsbatch -noterminal -noprint -log $logdir/batch1_$ Windows系统 0:00~9:00第一位需要手工补0,否则第一位是空格 set logdir=d:dwsaslogmart_wp set batchdir=d:dwprogmart_wpscriptsql set curtime1=%time:~0,2%%time:~3,2%%time:~6,2% set t1="%curtime1:~0,1%" if %t1% equ " " (set curtime=0%curtime1:~1,5%) else (set curtime=%curtime1:~0,6%) -sysin "%batchdir%" -nosplash -noicon -noprint -log "%logdir%batch1_%curtime%.log" 5.5. 输出SAS库、库成员(数据集、视图、索引、编录等)的详细信息 1. 输出SAS库信息、库成员列表信息 proc datasets lib=sashelp details; quit; 部分显示结果: 2. 输出某个数据集的详细信息 proc datasets lib=sashelp nolist; contents data=class varnum; quit; 显示结果: 27 / 31 3. 输出库中所有数据集的详细信息 proc datasets lib=sashelp nolist; contents data=_all_ varnum; quit; 输出数据集详细信息也可用proc contents,结果是一样的,详见SAS帮助。 5.6. 浏览器自动提示安装SAS图形插件 若没有安装SAS图形插件,是无法查看ActiveX图形报表的。可以在报表程序中加入一段代码,使得浏览器自动提示安装图形插件,用户只要点击提示即可下载。 /*方法一,若使用了%stpbegin; ... ; %stpend; 只要在头文件中定义系统宏即可。*/ %let _ODSOPTIONS=%nrstr(codebase='/download/software/'); /*方法二,在输出图形的ods html语句中加入一段codebase=代码。*/ /*建议把路径定义成宏加到头文件中,便于将来更改*/ %let sasgraph=/frame/dl/soft_ware/; ods html file=_webout metatext="&encode" style="&ostyle" codebase="&sasgraph"; 5.7. SAS SCL开发时使用增强型编辑器 默认情况下,在BASE SAS中打开SCL程序使用的是基本编辑器,显示的代码都是黑色文本,通过如下方法使用增强型编辑器,可语法高亮显示代码: 在SAS窗口输入命令: regedit 28 / 31 依次选择product/af/design time/source window,改变增强型编辑器选项所对应的值为Yes。 使用增强型编辑器的时候有时会碰到如下问题: 当用增强型编辑器打开SCL文件时,没有做任何改变退出后,有可能重运行的时候会报告如下错误: ERROR: has not been compiled." 要解决该问题,直接重新编译该SCL代码即可 5.8. 修复损坏的数据集 数据集、索引或catalog损坏时,可尝试使用以下代码修复,但不保证一定成功,无法修复时只能恢复备份。 proc datasets lib=mylib nolist; repair name; quit; 6. 常见问题 6.1. 自定义format中文转码问题 取数据集中数据生成format,再用此format转换变量值时,某些中文可能会出现转码问题,造成导出数据时产生问题,某些数据不正确。 29 / 31 例如:有一个代码对照表,item_id为代码,item_desc为中文描述,用此数据集生成字符型format,名为wp_item_desc。在处理实绩数据时,已有item_id变量,要增加一个变量,值为中文描述,采用put(item_id,$wp_item_desc.)可以得到中文描述。 现将数据导出为csv格式,采用方法一导出后发现,某些数字型变量sum值小于在sas中计算的值,但观测数是一样的; /*方法一*/ ods listing close; ods csv file="&fname"; proc print data=&download_tname noobs label; run; ods csv close; ods listing; 采用方法二导出后,发现少了2条观测。 /*方法二*/ proc export data=&download_tname OUTFILE="&fname" DBMS=CSV REPLACE; run; 但是导成dbf格式,观测数、sum值都与sas计算一致。 经分析,导成文本格式时,如果某些中文转码有问题,就会使得一部分数据有问题或无法导出,此问题一般很难发现,因为程序运行根本不会提示任何错误或警告。 另外,在OLAP中钻取明细时,钻取范围内的数据的字符如果有转码问题就会报错。 解决方法:不使用format,用merge勾连对照表取值,一般不会产生这个问题。 6.2. EG连接超时 EG远程连接服务器时,长时间不操作会断开连接,再执行程序或查看表等就会出错,无法再连接。SAS回复:EG用的是session验证,当session断开时,一定要重启session才行。 解决方法:只能先关闭EG再重新运行。 6.3. 导入csv文件时最后一列数字变为空 本地上传csv等文本格式文件到UNIX服务器,通过SAS程序导入数据时,若最后一列是数字型的,数值会变为空。此问题是由于本地保存文本文件时,每行最后的换行符是DOS格式的,若服务器是WINDOWS系统,则可以正确认出最后的DOS换行符,不作为字符导入,但在UNIX系统下不认,导入数据时会把DOS换行符作为最后一列中的字符导入。若最后一列是数字型的,因为导入了非数字的字符,就会变为空,若是字符型的,虽然表面没有问题,但实际上值中包含DOS换行符,在OLAP中就会出错。 解决方法一:规定好导入的csv文件里最后要多加一无用的列,导入后把最后一列去掉。 解决方法二:导入时最后一列总是以字符型导入,在临时数据集中对最后一列处理一下,用compress(lastvar, ,'s')去掉分隔字符,再转换为数字型。(注:SAS8不支持此种用法) 30 / 31 6.4. 中文字段值异常,导出csv文件数据不正确 在某些情况下,导出的csv文件数据会与dbf等格式不一致,总结发现可能是由于某些中文字段值有怪字符或乱码或截断不正常,导致生成文件时数据错位或双引号缺失等。 暂无好的解决方法。建议碰到此问题时导出为dbf格式。 6.5. CUBE使用format的限制 在CUBE中若使用自定义format,则format定义时label值的长度不能超过100,否则钻取明细数据时会提示错误。 6.6. ODS输出数据时造成误差 使用ODS输出数据时(ODS HTML、ODS CSV等),若没有指定变量的format,则系统会自动四舍五入数值,保留小数位数不定。若将输出的数据在excel中汇总计算,与直接在数据库中计算的数据比较会有一定误差,记录数较多时汇总的误差就会较大。要减小误差的话,在最后输出的临时数据集中对数字型变量设置format,保留较多的小数位数,如:format var1 32.4 var2 32.6 var3 best32.; 使用proc export导出数据一般不存在这个问题。 6.7. put函数使用自定义format的名称长度问题 运行如下代码可能会有警告信息 data temp001; set &source1; where put(ITEM_ID,$wp_item_fmlycode.) eq 'A07'; run; WARNING: Server is unable to execute the WHERE clause. NOTE: 从数据集 MART_000301_200811 读取了 750 个观测。 WHERE COMPRESS(PUT(ITEM_ID, $WP_ITEM100.))='A07'; NOTE: 数据集 001 有 750 个观测和 18 个变量。 原因:SPDS不支持format名称超过8位,但即使有警告信息,一般也不影响运行结果。 6.8. ODS输出为非HTML格式时中文乱码 某些情况下,输出HTML格式时中文显示正常,但输出为EXCEL或其它格式时中文乱码,这是因为浏览器能正确选择编码显示,而EXCEL等自动选择的编码不正确,要解决此问题可在%stpbegin之前加入如下代码: %let _ODSOPTIONS=%str(charset='GBK'); 6.9. 命令行模式下执行proc import或export报错 命令行下sas –nodms启动sas,执行proc import或者export,会报错: ERROR: Cannot open X display. Check display name/server access authorization. ERROR: Device does not support full-screen. 改为sas –nodms –noterminal启动sas,不报错。 31 / 31 附录一 希望大家积极总结整理自己用到的技巧,随时可以发到qinyuan@ ,将不定期更新到文档中。 参与人员名单 姓名 许楠 倪海风 俞飞豪 郁威 王道远 张晓蕾 3.1. 4.1. 4.2. 4.3. 4.4. 6.5. 程序 程序 程序 提供的技巧 SAS对宏引用符号&、&&、&&&、&&&&的处理机制 对SAS中的临时大表建立索引 对ODS中的大表在etl过程时创建索引 反复使用的大表按当期建立临时表,在后续程序中使用。 反复使用的SAS代码制作一个带参数的宏 CUBE使用format的限制 抓取200.6数据字典网页中的数据 sas交互式矩阵语言在产业损害预警模型中的应用(由于保密原因,不公开发布) 转置相关。 1 / 1
版权声明:本文标题:SAS编程技巧手册 内容由网友自发贡献,该文观点仅代表作者本人, 转载请联系作者并注明出处:http://www.freenas.com.cn/jishu/1705594612h491630.html, 本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌抄袭侵权/违法违规的内容,一经查实,本站将立刻删除。
发表评论