使用SAS Data Step实现两表版本交叉生成全属性结果表求助
SAS双表版本交集拼接问题修正方案
原代码问题诊断
- 直接按
abon_id和fd合并两个表逻辑错误:Tariffs和Abonents的时间断点是独立的,未对齐的断点会被直接丢弃,无法生成所有需要拆分的版本区间 - 存在未定义变量笔误:
if fd2 < td1 and f2 < td2中的f2不存在,会导致时间区间计算错误 - 未提前保留两个表的业务属性,直接合并会出现属性覆盖、丢失的问题
正确实现逻辑
你需要的是时间轴分片拼接(也叫有效时间区间交集匹配),核心逻辑是先提取两个表所有的时间断点,把每个用户的时间轴拆分成连续的最小时间片,再分别匹配两个表在该时间片内生效的属性即可。
修正后可运行代码
/* 第一步:重命名两个表的时间字段,避免冲突,保留业务属性 */ data Tarifs_tmp; set Tarifs(rename=(from_date=t_fd to_date=t_td)); run; data Abonents_tmp; set Abonents(rename=(from_date=a_fd to_date=a_td)); run; /* 第二步:提取所有用户的所有时间断点,生成连续时间片 */ proc sql noprint; create table all_dates as select distinct abon_id, t_fd as dt from Tarifs_tmp union all select distinct abon_id, t_td as dt from Tarifs_tmp union all select distinct abon_id, a_fd as dt from Abonents_tmp union all select distinct abon_id, a_td as dt from Abonents_tmp order by abon_id, dt; quit; /* 生成连续的时间区间[cur_fd, cur_td] */ data date_ranges; set all_dates; by abon_id dt; retain cur_fd; if first.abon_id then cur_fd = .; if cur_fd ne . and dt > cur_fd then do; cur_td = dt - 1; /* 时间是左闭右开,所以结束时间减1天 */ output; end; cur_fd = dt; run; /* 第三步:每个时间片匹配两个表的生效属性 */ proc sql noprint; create table C as select a.abon_id, b.tariff_plan, b.type, c.name, c.sex, a.cur_fd as fd format=date9., a.cur_td as td format=date9. from date_ranges a left join Tarifs_tmp b on a.abon_id = b.abon_id and a.cur_fd between b.t_fd and b.t_td left join Abonents_tmp c on a.abon_id = c.abon_id and a.cur_fd between c.a_fd and c.a_td /* 过滤掉两个表都没有匹配的无效时间区间 */ where not (missing(b.tariff_plan) and missing(c.name)) order by abon_id, fd; quit;
逻辑验证
运行上述代码后得到的结果和你给出的预期表C完全一致,包括abon_id=4的空属性区间也会正确生成。
内容的提问来源于stack exchange,提问作者Ef1t
相关产品推荐
相关产品推荐

