SAS中如何使用HASH对象实现1=1条件的左连接
1=1无条件左连接的HASH等价实现方案
实现思路
无条件1=1左连接本质是将前序连接结果的每一行,与筛选后的costs子表的所有行做笛卡尔积,左连语义保证前序结果哪怕没有匹配到costs行也会保留,costs对应字段为空。实现时可以给筛选后的costs子表统一设置固定虚拟键,用虚拟键做HASH匹配即可实现全量遍历。
正确实现代码
data indirect_costs; /* 预先声明所有变量的PDV结构 */ if 0 then set dpd efforts&costprod. costs(where=(_name_='avg_effort_cost')); if _n_ = 1 then do; /* 加载第一个左连接的hash表:efforts&costprod.,关联键client_ref,支持多值匹配 */ declare hash h_cf(dataset: "efforts&costprod.", hashexp: 15, multidata: 'Y'); h_cf.defineKey('client_ref'); h_cf.defineData(all: 'Y'); h_cf.defineDone(); /* 加载第二个1=1连接的hash表:筛选后的costs,自动生成固定虚拟键dummy=1做关联 */ declare hash h_df(dataset: "costs(where=(_name_='avg_effort_cost') dummy=1)", hashexp: 15, multidata: 'Y'); h_df.defineKey('dummy'); /* 虚拟关联键,所有行值都为1,匹配时可遍历全表 */ h_df.defineData(all: 'Y'); h_df.defineDone(); /* 声明h_df的迭代器,用来批量遍历所有costs匹配行 */ declare hiter iter_df('h_df'); end; set dpd; /* 先匹配第一个左连接的表b,按fnum关联 */ rc_cf = h_cf.find(key: fnum); /* b表没有匹配的情况也要保留行,先将b表对应字段置空 */ if rc_cf ne 0 then call missing(of efforts&costprod.._all_); /* 遍历b表的所有匹配行 */ do while(rc_cf = 0); /* 每拿到一条b的匹配行,遍历所有c表的行,实现1=1连接 */ rc_df = iter_df.first(); if rc_df ne 0 then do; /* c表为空的情况,直接输出当前行,c字段全空 */ call missing(of costs._all_); output; end; do while(rc_df = 0); output; rc_df = iter_df.next(); end; /* 找下一条b的匹配行 */ rc_cf = h_cf.find_next(key: fnum); end; drop rc_cf rc_df dummy; run;
关键修正点说明
- 给costs子表新增固定值虚拟键关联,不需要真实业务键即可实现全量遍历,完美等价1=1的连接语义
- 调整了遍历逻辑:每匹配到1条b表的行,就遍历所有c表的行输出,符合笛卡尔积的计算逻辑
- 补全了costs表的where筛选条件,避免加载全量costs无效数据
- 兼容左连语义:b表或c表无匹配时,对应字段自动置空并保留主表行,和原SQL结果完全一致
内容的提问来源于stack exchange,提问作者py14ak
相关产品推荐
相关产品推荐

