使用SAS first.variable/last.variable合并日期区间的异常问题
问题根源分析
你当前的代码问题出在排序和分组逻辑完全忽略了id维度,且没有区分同一id下被其他code打断的同code区间。之前你按code排序,会把不同id、不同时间段的同code记录强行凑在一起,自然会把1A的ABC两个不连续区间错误合并,导致起始日期不符合预期。
修正方案
根据你的期望结果,核心需求是:同一id下,连续的同code记录合并为单个日期区间;如果code被其他值打断,则仅保留该code最后一段连续区间。下面是两种实现方式:
方式一:数据步直接处理(高效简洁)
先按id和时间排序,再用retain跟踪连续区间的起始日期,最后输出每个连续区间的合并结果:
/* 第一步:按id+时间顺序排序,确保每个id的记录按时间流转排列 */ proc sort data=example out=example_sorted; by id valid_from; run; /* 第二步:合并连续的同code区间,仅保留每个id+code的最后一段连续区间 */ data collapse_val_dates; set example_sorted end=eof; by id; retain current_from current_code; /* 初始化或重置当前区间的起始日期和code */ if first.id then do; current_from = valid_from; current_code = code; end; /* 当code变化时,更新当前区间(仅记录最后一段) */ if ne(code, current_code) then do; current_from = valid_from; current_code = code; end; /* 到达当前id的最后一条记录时,输出最终区间 */ if last.id then do; id = id; code = current_code; valid_from = current_from; valid_to = valid_to; output; end; drop current_from current_code; format valid_from valid_to IS8601DA10.; run;
方式二:分组标记+SQL合并(逻辑清晰易扩展)
先给每个连续的code区间分配组号,再筛选出每个id+code的最后一组进行合并:
/* 第一步:按id+时间排序 */ proc sort data=example out=example_sorted; by id valid_from; run; /* 第二步:给每个连续的code区间标记组号 */ data with_group; set example_sorted; by id; retain group 0; /* 当是新id,或当前code与上一条不同时,组号+1 */ if first.id or ne(code, lag(code)) then group + 1; run; /* 第三步:获取每个id+code的最大组号(即最后一段连续区间) */ proc sql; create table max_group as select id, code, max(group) as max_group from with_group group by id, code; quit; /* 第四步:合并最后一段连续区间的起止日期 */ proc sql; create table collapse_val_dates as select w.id, w.code, min(w.valid_from) as valid_from format=IS8601DA10., max(w.valid_to) as valid_to format=IS8601DA10. from with_group w inner join max_group m on w.id = m.id and w.code = m.code and w.group = m.max_group group by w.id, w.code order by w.id, valid_from; quit;
结果验证
两种方式都会得到你期望的输出:
| id | code | valid_from | valid_to |
|---|---|---|---|
| 1A | DEF | 2015-03-31 | 2019-06-29 |
| 1A | ABC | 2019-06-30 | 2019-09-16 |
| 1B | MNO | 2015-04-22 | 2015-06-20 |
| 1B | PQR | 2015-06-21 | 2015-06-30 |
| 1B | STU | 2015-07-01 | 2015-08-31 |
| 1B | VWX | 2015-09-01 | 9999-12-31 |
内容的提问来源于stack exchange,提问作者Kermit
相关产品推荐
相关产品推荐

