7楼的substr有个小错误,第三个参数应该是截长。其次,关于where的语句所要表达的意思,我来解释一下吧,其实是having语句,该表若每天都有记录即持有则视为连续,因此sum(n)就是持有的天数,dif则是时长,因此天数等于时长就代表了连续,反之两者之间的差则是代表了未持有的天数,若差不为零就不构成了连续。
不过关于楼主的定义我有一些别的看法。
从楼主给到的数据来看,貌似并不是每天都有记录,而date的值都为季度末的最后一天,如果是这样,那date其实就可以作为季度。因此猜想:
1 此数据是在季度末最后一天的状态。有记录则代表此季度fund持有该stock,无记录则代表此季度fund不持有。
2 连续持有4个季度应该是指对于某个fund,只要有连续四个季度及以上持有某stock的记录,则就视为满足条件。季度的连续性应该包括跨年吧。
举例:对于某个fund,持有某个stock的时间点
若为:2005-03-31,2005-06-30,2005-12-31,则该stock不满足条件
若为:2005-06-30,2005-09-30,2005-12-31,2006-01-31,则该stock满足条件
若为:2004-06-30,2005-06-30,2005-09-30,2005-12-31,2006-01-31,虽然第一时间点与第二时间点相差1年,但后四个时间点仍然构成连续四个季度,因此则该stock满足条件
在这样的前提下:
第一步:
- proc sql;
- create table fund01 as
- select
- distinct *,
- input(date,yymmdd10.) as td,
- min(td) as min_dte
- from fund
- group by fund_code,stock
- order by fund_code,stock,td
- ;
- quit;
复制代码第二步:
- data fund02(keep=fund_code stock hsy);
- set fund01;
- by fund_code stock td;
- length hsy $ 30;
- retain hsy;
- if first.stock then call missing(hsy);
- /*计算季度差,建议采用'30/360',对于本数据集更准确。
- 由于此例,date的特殊性,yrdif函数计算结果的小数位只有0,.25,.5,.75四种可能。*/
- t=yrdif(min_dte,td,'30/360')*4;
- if t=1 then hsy=compress(hsy)||'1';
- else if t>1 then hsy=compress(hsy)||repeat('0',t-2)||'1';
- else hsy='1';
- if last.stock;
- run;
复制代码第三步:
- proc sql;
- create table result as
- select
- a.*,
- case when b.fund_code and b.stock then 1 else 0 end flg
- from fund as a
- left join fund02(where=(hsy contains '1111')) as b
- on a.fund_code=b.fund_code
- and a.stock=b.stock
- ;
- quit;
复制代码哪位高手有更好的方法,希望指点。