如何使用 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 解决方案往往表现较差比其他选择。