八:modify语句((一个指针,两个pdv))
merge语句和update语句对数据集横向合并的主要功能还只能体现在匹配访问上,如通过by语句,对每个by组中的匹配数据集进行修改或更新,对于非常庞大的数据集需要定期更新,并且每次更新的观测对象是动态的时候,merge和update会消耗更多的资源,而是用modify可以通过高效的访问机制来实现这个需求。
四种语法:
1.匹配访问
Data master_data;
Run;
注:除非使用output语句,否则data步后面只能接一个数据集,并且modify后面的第一个数据集必须和data步后面的数据集同名;
Data master_data;
Run;
注:
更新数据集在主数据集没有找到主数据集key=对应的变量值,系统会设置自动变量_error_值为1,并在日志报错中显示该变量,
索引访问和匹配访问的不同点:
匹配访问中更新数据集同名变量会自动覆盖主数据集;索引访问会被当做不同的变量;
对于更新数据集出现by重复值的处理,索引访问会报错并终止程序,不过可以通过unique来纠正。
3.观测序号访问
Data master_data;
Run;
如果更新数据集在主数据集中没有找到point=对应的变拉直,系统会自动设置自动变量_error_的值为1,另外point=有可能陷入死循环,需要配合stop使用。
4.顺序访问
Data master_data;
Run;
注:关于自动变量_iorc_,当运行modify语句时,_iorc_变量自动生成,包含系统每次运行modify语句时返回的I/O操作码,以匹配访问为例,如果主数据集by变量值在更新数据集中存在,自动变量_iorc_返回0,如果主数据集by变量值在更新数据集中不存在,不产生自动变量_iorc_,但是如果更新数据集by变量值在主数据集中不存在,自动变量_iorc_会返回一个非0值。
Eg:
修改观测值:
Data
Run;
程序解读:首先编译,创建一个pdv,此时数据集a1处于打开状态,但是由于modify的独特机制,系统并没有另外开辟外存空间,所以整个程序运行过程中,在磁盘设备上看不到数据集a1的临时数据集。
由于modify语句采用动态where语句,而where查询动作是在pdv之前完成,因此当系统读到if x=2的时候,数据指针在pdv之前就指向该观测值并修改,最后由pdv输出,且输出的方式不是output而是replace方式,除非用户指定output。系统会默认采用replace方式输出。当用output的时候,喜欢很可能会陷入死循环。
商业应用:定期更改客户交易总额
主数据集:
Data master_trans;
;
Run;
交易数据集:
Data day_trans;
Input user_id
Cards;
102
;
Run;
程序实现:
data master_trans;
modify master_trans day_trans;
by user_id;
trans_amt=trans_amt day_amt;
if _iorc_=0 then replace;
else do;trans_amt=day_amt;_error_=0;output; end;
run;
程序解读:
第一步:编译阶段,系统产生两条pdv,一条为master_trans所有,另一条为day_trans所有;
第二步:Master_trans的数据指针直接指向master_trans的第二条观测,同时day_trans的指针指向day_trans的第一条观测,执行累加语句trans_amt=trans_amt day_amt;执行完后,发现还有day_trans中还有一条观测与master_trans中的第二条观测匹配,于是,day_trans的数据指针指向day_trans的第三条观测,再次执行累加语句,知道day_trans中没有与之匹配的数据,系统会继续执行以下语句,接下来if _iorc_=0 then replace;被执行,因为该匹配是成功匹配,所以系统返回自动变量_iorc_=0,然后执行replace语句,
重复执行第二步,系统同样以replace方式输出master_trans的第三条观测,
此时master_trans的数据指针指向master_trans末尾,但是day_trans还有最后一条观测没有在master_trans中被发现,于是系统返回一个非零的自动变量_iroc_,此时将执行else后面的语句,最后执行output的输出方式到master_trans的末尾。
当然也可以用sql和merge执行实现:
proc sql;
create table temp as
select
user_id
,sum(day_amt) as day_amt
from day_trans
group by 1;
quit;
proc sort data=master_trans;by user_id;run;
proc sort data=temp;by user_id;run;
data master_trans;
merge master_trans temp;
by user_id;
if trans_amt eq . then trans_amt=COALESCE(trans_amt,day_amt);
else trans_amt=sum(trans_amt,day_amt);
run;
总结:modify常用于根据某些需求条件更新特定变量组,或者对主数据集的某些变量做历史累加。