在SQL过程步中使用SAS数据步的选项
Using Data Set Options in PROC SQL
本文主要讲解了在SQL过程步中使用SAS数据步的选项,包括DROP、KEEP、LABEL、COMPRESS、SORTEDBY、WHERE和RENAME等,灵活地使用这些选项可以让我们的SQL过程步更有效、更简洁。附录创建了三个数据集,方便我们进行讲解。
1 DROP和KEEP
在使用用SQL过程步时,我们可以用select选择结果要保留的列,或者用*选择所有的列。但是如果我们要选择除某一两个列之外的所有的列,这时就要使用将其他的列全部都写一遍,是不是很麻烦。这时我们就可以用到DROP来删除这几个不需要的列。例如我们要保留除A1和A3列之外的SCORES数据集中的所有数据:
%let label=Scores Data Set without A1 and A3;
proc sql;
create table Scores1(label="&label") as
select *
from Scores(drop=A1 A3);
quit;
此外我们还可以直接在CREATE TABLE语句后面加上Drop或Keep选项来删除或保留指定的列:
proc sql;
create table Scores2(label="&label" drop=A1 A3) as
select *
from Scores;
quit;
下面一个例子是用多种方法来实现保留除B开头以外的所有列:
例1:这里KEEP选项里的A1-A10表示了变量范围,即:A1到A10共10个变量。注意这里的’ -’表示变量范围,如果在SQL过程步的select语句中,则表示用A1减去A10的值来创建一个新的变量。
proc sql;
create table only_As_1(label='Scores for A Parameters Only') as
select *
from Scores(keep=Subject_id Visit A1-A10);
quit;
例2: 这里用’--’表示名字范围,B1--B10表示从B1到B10共10个变量
proc sql;
create table only_As_2(label='Scores for A Parameters Only') as
select *
from Scores(drop=B1--B10);
quit;
例3:’B :’也是名字范围,指所有以B开头的变量
proc sql;
create table only_As_3(label='Scores for A Parameters Only') as
select *
from Scores(drop= B:);
quit;
例4:_numeric_指所有的数值型变量,与之相对应的是_character_,表示所有的字符型变量。
proc sql;
create table only_As_4(label='Scores for A Parameters Only') as
select *
from Scores(keep=Subject_ID _numeric_);
quit;
2 LABEL
这个选项在上面几个例子中已经讲解。
3 COMPRESS
COMPRESS主要是用来减少数据集的存储空间,在SQL过程步使用COMPRESS选项进行数据压缩时,我们需要在CREATE TABLE语句后要压缩的数据表后面加入该选项。
proc sql;
create table only_Bs(compress=yes) as
select *
from Scores(drop=A1-A10);
quit;
NOTE: 压缩的数据集 WORK.ONLY_BS 大小减少了百分之 54.85。
压缩为 484 页;不压缩将会要求 1072 页。
NOTE: 表 WORK.ONLY_BS 创建完成,有 60000 行,12 列。
4 RENAME
RENAME的作用是更改数据集的变量的名称,例如我们要将SCROES中的数组A的所有变量加上前缀’Base_’,你可以用select语句一个一个地更改名字,也可以用rename数据步选项。
例:用Select一个一个地进行更名
proc sql;
create table Baseline_A_1 as
select subject_id,
a1 as base_a1,
a10 as base_a10
from Scores
where visit=1;
quit;
例:用RENAME选项
proc sql;
create table baseline_A_2 as
select *
from Scores(rename=(a1-a10=base_a1-base_a10) drop=b:)
where visit=1;
quit;
注意,这里我们将数组A的名字改为以B开头的变量,而后面一句drop=b:是不是会把刚才更名完后的变量也删除掉。结果是不会的,因为Keep和Drop选项是在Rename选项之前就执行了。
下面来讲一个我们经常遇到的情况:两个表的内连接。例如我们要对表SCORES和SURGERY进行内连接,表SCORES的主键为subject_id,而表SURGERY的主键为sid,这时,我们一般的内连接语句为:
proc sql feedback _method;
create table Scores_Surg1 as
select *
from Scores T1, Surgery T2
where T1.subject_id=T2.sid and
T1.visit=T2.visit;
quit;
另一种方法就是先将SURGERY中的sid改名为subject_id,然后运用数据表的inner join来进行数据表的内连接:
proc sql feedback _method;
create table Scores_Surg2 as
select *
from Scores T1
natural inner join
Surgery(rename=(sid=subject_id)) T2;
quit;
另外,我们还可以遇到列名为SAS关键词时,会出现一些错误,例如:
proc sql _method;
create table caseLT4_1 as
select *
from Surgery
where case lt 4;
quit;
这里,where case这一句,SAS会认为这是一个条件操作的开始(case when…then… end),因此会出现错误。这时我们可以先将该列名更名后再进行where语句。例如:
proc sql _method;
create table caseLT4_2 as
select *
from Surgery(rename=(case=case_id))
where case_id lt 4;
quit;
这时case已改名为case_id
5 SORTEDBY
该选项主要指明数据集已用哪些变量进行排序,这会增加SQL过程步的效率。本人对该选项用得比较少,对效率优化也做得比较少,就不再介绍,请大家阅读相关文献。
6 WHERE
WHERE选项在SQL过程步中,主要用于取数据子集或指定连接条件。Surgery数据集中,visit小于16的客户在Scores数据中增加一个标识。一般的方法如下:
proc sql;
create table scores_surglt16 as
select T1.*,
case when ILV2.Visit gt 0 then 'Y' end as Surgery_Flag
from Scores as T1
left join
( select *
from Surgery
where Visit lt 16) as ILV2
on T1.visit=ILV2.visit and
T1.subject_id=ILV2.sid;
quit;
这里得到的结果是Surgery数据集中,visit小于16的10个客户,在Scores数据集中生成的新Surgery_Flag的值为Y。我们可以用where选项来简化上述代码:
proc sql;
create table scores_surglt16_2 as
select T1.*,
case when T2.Visit gt 0 then 'Y' end as Surgery_Flag
from Scores T1
natural left join
Surgery(where=(visit lt 16)
rename=(sid=subject_id)) T2;
quit;
where的另一个用法是与in选项结合。例如要实现模糊匹配,我们可以用like以及通配符%:
proc sql _method;
create table ex11a as
select *
from scores
where subject_id like '100-%' or
subject_id like '20%';
quit;
我们也可以用where和in选项来简化上述代码:
proc sql _method;
create table ex11b as
select *
from scores(where=(subject_id in: ('100-','20')));
quit;
7 附录
data Tx (label='Treatment Code Information' drop=a);
do a=1 to 3000;
Subject_No=a;
if a le 1500 then center =100; else center=200;
random_date=int(15000+20*ranuni(315975)); format random_date mmddyy10.;
if ranuni(97511) lt .5 then tx=1; else tx=2;
output;
end;
label tx='Treatment Code'
random_date='Randomization Date'
subject_no="Subject Number";
run;
data Scores(label='Recorded Scores at Visits' drop=j c);
length Subject_ID $8 Visit 8 A1-A10 8 B1-B10 $20;
array A[10]; array B[10];
do c=1 to 3000;
if c le 1500 then subject_id=compress('100-'||put(c,z4.));
else subject_id=compress('200-'||put(c, z4.));
do Visit=1 to 20;
do j=1 to 10;
a[j]=j*ranuni(j);
b[j]=left(put(.5+j**2*ranuni(j),7.3));
end;
output;
end;
end;
format a: 5.2;
run;
data Surgery;
length SID $8 Visit 8 case 8;
do k=5 to 3000 by 197;
if k lt 1500 then SID=compress('100-'||put(k,z4.));
else SID=compress('200-'||put(k, z4.));
Visit=10+int(10*ranuni(971156));
case+1;
drop k;
output;
end;
run;
0 comments:
Post a Comment