如何在SAS中合并数据集并生成指定目标变量的技术问询
解决SAS数据集匹配并生成单行结构的问题
看起来你已经走对了第一步(用PROC SQL左连接),但因为data1里每个ID有多条记录,导致连接后出现多行,没法直接得到每个ID一行的目标结构。下面我给你两种实用的解决方案,你可以根据自己的需求选择:
方法一:用PROC SQL直接聚合生成目标数据集
这种方法最简洁,通过聚合函数和CASE WHEN来提取匹配的Code值,直接输出每个ID一行的结果:
proc sql; create table final_data as select d2.ID, max(case when d1.Code = d2.code1 then d1.Code else '' end) as Code1_a, max(case when d1.Code = d2.code2 then d1.Code else '' end) as Code2_a from data2 d2 left join data1 d1 on d2.ID = d1.ID group by d2.ID; quit;
说明:
- 用
case when判断data1的Code是否匹配data2的code1/code2,匹配的话返回Code值,否则返回空字符串 max()聚合函数的作用是:对于同一个ID,即使有多个匹配(比如data1里有多个和code1相同的Code),它会保留非空的那个值(如果只有一个匹配,就是它本身;如果有多个相同的,结果也一样)- 如果你的Code是数值型,把
''改成.即可
方法二:先合并再用DATA步处理去重
如果你更习惯用DATA步,也可以先合并两个数据集,再按ID分组保留需要的匹配值:
/* 第一步:合并两个数据集,保留所有data2的记录以及data1中匹配的记录 */ data merged; merge data2 (in=a) data1 (in=b); by ID; if a; /* 只保留data2中存在的ID,和左连接效果一致 */ run; /* 第二步:按ID分组,提取匹配的Code1_a和Code2_a */ data final_data; set merged; by ID; retain Code1_a Code2_a; /* 保留上一行的变量值 */ if first.ID then do; /* 每个ID的第一条记录初始化变量 */ Code1_a = ''; Code2_a = ''; end; /* 匹配code1则赋值给Code1_a */ if Code = code1 then Code1_a = Code; /* 匹配code2则赋值给Code2_a */ if Code = code2 then Code2_a = Code; if last.ID then output; /* 每个ID的最后一条记录才输出 */ drop Code last4_Code code1 code2; /* 去掉不需要的中间字段 */ run;
说明:
retain语句用来在循环中保留变量值,这样即使ID的某一行不匹配,之前赋值的结果也不会丢失first.ID和last.ID是BY组处理的自动变量,用来判断当前行是ID组的第一条还是最后一条- 同样,如果Code是数值型,初始化时用
.代替''
额外说明
如果data1中同一个ID对应多个和code1匹配的Code(比如多个不同的Code都等于code1),上面的方法会保留最后一个匹配的值(方法二)或者最大的那个(方法一)。如果你需要把所有匹配的值用逗号分隔,可以把方法一中的max()换成catx(',', ...),比如:
proc sql; create table final_data as select d2.ID, catx(',', collect(case when d1.Code = d2.code1 then d1.Code else '' end)) as Code1_a, catx(',', collect(case when d1.Code = d2.code2 then d1.Code else '' end)) as Code2_a from data2 d2 left join data1 d1 on d2.ID = d1.ID group by d2.ID; quit;
这样Code1_a会把所有匹配code1的Code用逗号连接起来,适合有多个匹配值的场景。
内容的提问来源于stack exchange,提问作者ckp
相关产品推荐
相关产品推荐

