Hash join等价于PROC SQL之间

时间:2017-05-25 18:45:52

标签: sql join hash sas between

我通常使用PROC SQL,当我加入表时也有日期条件(即target_date介于start_date和end_date之间)。

在考虑内部联接时,我已经能够成功地将其转换为散列连接:

data hash_join;
if _n_ = 1 then do;
    declare hash add1(dataset:'table_2',multidata: 'Y');
    add1.defineKey('key_1');
    add1.defineData('start_date','end_date','value_1');
    add1.defineDone();
end;

format 
    start_date date9.
    end_date date9.
    value_1 10.5
;

set table_1 (keep=key_1 target_date);

if add1.find() = 0 then do until (add1.find_next());
    if start_date le target_date le end_date then output;
end;
run;

与以下内容相同:

proc sql;
create table sql_join as select
b.start_date,
b.end_date,
b.value_1,
a.key_1,
a.target_date
from table_1 a
inner join table_2 b
on  a.key_1 = b.key_1 and
a.target_date between b.start_date and b.end_date
;quit;

我很难搞清楚左边连接的等价物。例如,如果某些东西没有加入,我想输出,我认为这很简单:

if add1.find() ne 0 then output;

如果它加入并且日期介于两者之间,那似乎也很简单:

if add1.find() = 0 then do until (add1.find_next());
    if start_date le target_date le end_date then output;
end;

但是如何从table_1获取可能加入的其余记录,但是在start_date和end_date之间没有target_date?例如,假设table_2是销售的start_date和end_date,并且直到2月1日才开始销售key_1 ='Clothes'。如果我的table_1在1月1日有“衣服”和销售,它将加入密钥,但我想输出空白值。关于如何做到这一点的任何想法?

非常感谢任何帮助!

2 个答案:

答案 0 :(得分:3)

我认为你只需要跟踪某些东西是否有钥匙,但不在以下范围内:

if add1.find() ^=0 then output;
else do;
   found = 0;
   do until (add1.find_next());
       if start_date le target_date le end_date then do;
          output;
          found=1;
       end;
   end;
   if ^found then output;
end;

没有要测试的数据,所以这只是我用SO编码。如果它不起作用,请告诉我。

答案 1 :(得分:3)

您只需要跟踪您是否找到了匹配项。由于您没有使用哈希查找来跟踪事物的“中间”部分,因此您无法使用它,所以您必须自己完成。

请参阅此示例。在这里,我修改SASHELP.CLASS看起来像你的输入表,然后添加一些逻辑,看看是否找到了任何东西。

data table_1;
  set sashelp.class;
  rename age=target_date name=key_1;
  drop height weight;
run;

data table_2;
  set sashelp.class;
  do _i = 1 to mod(_n_,3);
    start_date = age-3+_i;
    end_date = age+1-_i;
    if start_date le end_date then output;
  end;
  rename name=key_1 height=value_1;
  keep height weight start_date age end_date name;
run;

data hash_join;
if _n_ = 1 then do;
    declare hash add1(dataset:'table_2',multidata: 'Y');
    add1.defineKey('key_1');
    add1.defineData('start_date','end_date','value_1');
    add1.defineDone();
end;

format 
    start_date date9.
    end_date date9.
    value_1 10.5
;

set table_1 (keep=key_1 target_date);

if add1.find() = 0 then do until (add1.find_next());
    if start_date le target_date le end_date then do;
      found=1;
      output;
    end;
end;
call missing(of value_1);  *full list of values to clear - all of hash data elements;
if not (found) then output;
run;