如何使用 sas HASH 对象执行内部连接
How do you perform an inner join using the sas HASH object
据我了解,这是一个左连接:
data deb;
if 0 then set ids DMREPORT;
if _n_=1 then do;
ds="DMREPORT";
declare Hash a (dataset:ds, multidata:'Y',hashexp:15);
a.DefineKey ('debt_item_reference','system_date');
a.DefineData (all:'Y');
a.DefineDone ();
end;
set ids;
rc=a.find(key:fnum, key:hdat);
do while(rc=0);
output;
rc=a.find_next();
end;
drop ds;
run;
如何执行内部联接,HoH 等效项又如何呢?
我尝试了什么:
data bla;
if 0 then set A B;
If _n_=1 then do;
declare Hash a (dataset:'A', multidata:'Y',hashexp:15);
a.DefineKey ('Key1','Key2');
a.DefineData (all:'Y');
a.DefineDone ();
declare Hash b (dataset:'B', multidata:'Y',hashexp:15);
b.DefineKey ('key1','key2');
b.DefineData (all:'Y');
b.DefineDone ();
end;
rc=a.find();
rb=b.find();
do while(rc=0 and rb=0)
output;
rc=a.find_next();
rb=b.find_next();
end;
内连接与左连接只是您是否保留不匹配的“源”数据集行的问题。
术语:“源”数据集 = 左数据集,“目标”数据集 = 右数据集。
- 外连接:保留“源”数据集中的所有行,追加“目标”中匹配的所有列,然后追加“目标”中不匹配的所有行
- 左连接:保留“源”数据集中的所有行,附加“目标”中匹配的任何列
- 内部联接:仅保留“源”中与“目标”行匹配的行,追加“目标”中的列
这是一个很常见的用例。在散列的情况下,if rc eq 0 then output
是使某些内容成为内部联接的原因 - 如果有默认值 output
则它是左联接。
内部联接:
rc = h.find();
if rc eq 0 then output;
左连接:
rc = h.find();
output;
外连接 - 首先找到所有匹配项,将它们从匹配项中删除,然后遍历散列 table 以找到不匹配的行并将它们也输出:
rc = h.find();
output;
rc_r = h.remove();
*eof defined in the set statement (end=eof);
*hi is hiter for h;
if eof then do;
rc = hi.first();
do while rc eq 0;
output;
rc = hi.next();
end;
end;
您不会像现在这样使用两个散列 table,通常情况下,这会使事情变得更加复杂和缓慢。
这是一个实际的例子:
data classfit_male;
set sashelp.classfit;
if sex='M';
run;
data left_join;
set sashelp.class;
if 0 then set classfit_male;
if _n_ eq 1 then do;
declare hash h_cf(dataset:'classfit_male');
h_cf.defineKey('name');
h_cf.defineData(all:'y');
h_cf.defineDone();
end;
rc_cf = h_cf.find();
output;
call missing(of _all_);
run;
data inner_join;
set sashelp.class;
if 0 then set classfit_male;
if _n_ eq 1 then do;
declare hash h_cf(dataset:'classfit_male');
h_cf.defineKey('name');
h_cf.defineData(all:'y');
h_cf.defineDone();
end;
rc_cf = h_cf.find();
if rc_cf eq 0 then output;
call missing(of _all_);
run;
data outer_join;
set sashelp.class(where=(age le 13)) end=eof;
if 0 then set classfit_male;
if _n_ eq 1 then do;
declare hash h_cf(dataset:'classfit_male');
h_cf.defineKey('name');
h_cf.defineData(all:'y');
h_cf.defineDone();
declare hiter hi_cf('h_cf');
end;
rc_cf = h_cf.find();
output;
rc_rm = h_cf.remove();
call missing(of _all_);
if eof then do;
rc_cf = hi_cf.first();
do while (rc_cf eq 0);
output;
rc_cf = hi_cf.next();
end;
end;
run;
我上面写的不处理每个键的多行;这个概念并没有真正改变,你只需要添加 find_nexts 来使它工作,但老实说我倾向于发现如果每个键哈希有多行 table 解决方案往往表现较差比其他选择。
据我了解,这是一个左连接:
data deb;
if 0 then set ids DMREPORT;
if _n_=1 then do;
ds="DMREPORT";
declare Hash a (dataset:ds, multidata:'Y',hashexp:15);
a.DefineKey ('debt_item_reference','system_date');
a.DefineData (all:'Y');
a.DefineDone ();
end;
set ids;
rc=a.find(key:fnum, key:hdat);
do while(rc=0);
output;
rc=a.find_next();
end;
drop ds;
run;
如何执行内部联接,HoH 等效项又如何呢?
我尝试了什么:
data bla;
if 0 then set A B;
If _n_=1 then do;
declare Hash a (dataset:'A', multidata:'Y',hashexp:15);
a.DefineKey ('Key1','Key2');
a.DefineData (all:'Y');
a.DefineDone ();
declare Hash b (dataset:'B', multidata:'Y',hashexp:15);
b.DefineKey ('key1','key2');
b.DefineData (all:'Y');
b.DefineDone ();
end;
rc=a.find();
rb=b.find();
do while(rc=0 and rb=0)
output;
rc=a.find_next();
rb=b.find_next();
end;
内连接与左连接只是您是否保留不匹配的“源”数据集行的问题。
术语:“源”数据集 = 左数据集,“目标”数据集 = 右数据集。
- 外连接:保留“源”数据集中的所有行,追加“目标”中匹配的所有列,然后追加“目标”中不匹配的所有行
- 左连接:保留“源”数据集中的所有行,附加“目标”中匹配的任何列
- 内部联接:仅保留“源”中与“目标”行匹配的行,追加“目标”中的列
这是一个很常见的用例。在散列的情况下,if rc eq 0 then output
是使某些内容成为内部联接的原因 - 如果有默认值 output
则它是左联接。
内部联接:
rc = h.find();
if rc eq 0 then output;
左连接:
rc = h.find();
output;
外连接 - 首先找到所有匹配项,将它们从匹配项中删除,然后遍历散列 table 以找到不匹配的行并将它们也输出:
rc = h.find();
output;
rc_r = h.remove();
*eof defined in the set statement (end=eof);
*hi is hiter for h;
if eof then do;
rc = hi.first();
do while rc eq 0;
output;
rc = hi.next();
end;
end;
您不会像现在这样使用两个散列 table,通常情况下,这会使事情变得更加复杂和缓慢。
这是一个实际的例子:
data classfit_male;
set sashelp.classfit;
if sex='M';
run;
data left_join;
set sashelp.class;
if 0 then set classfit_male;
if _n_ eq 1 then do;
declare hash h_cf(dataset:'classfit_male');
h_cf.defineKey('name');
h_cf.defineData(all:'y');
h_cf.defineDone();
end;
rc_cf = h_cf.find();
output;
call missing(of _all_);
run;
data inner_join;
set sashelp.class;
if 0 then set classfit_male;
if _n_ eq 1 then do;
declare hash h_cf(dataset:'classfit_male');
h_cf.defineKey('name');
h_cf.defineData(all:'y');
h_cf.defineDone();
end;
rc_cf = h_cf.find();
if rc_cf eq 0 then output;
call missing(of _all_);
run;
data outer_join;
set sashelp.class(where=(age le 13)) end=eof;
if 0 then set classfit_male;
if _n_ eq 1 then do;
declare hash h_cf(dataset:'classfit_male');
h_cf.defineKey('name');
h_cf.defineData(all:'y');
h_cf.defineDone();
declare hiter hi_cf('h_cf');
end;
rc_cf = h_cf.find();
output;
rc_rm = h_cf.remove();
call missing(of _all_);
if eof then do;
rc_cf = hi_cf.first();
do while (rc_cf eq 0);
output;
rc_cf = hi_cf.next();
end;
end;
run;
我上面写的不处理每个键的多行;这个概念并没有真正改变,你只需要添加 find_nexts 来使它工作,但老实说我倾向于发现如果每个键哈希有多行 table 解决方案往往表现较差比其他选择。