之间的 PROC SQL 上的哈希连接等效项

Posted

技术标签:

【中文标题】之间的 PROC SQL 上的哈希连接等效项【英文标题】:Hash join equivalent on PROC SQL between 【发布时间】:2017-05-25 18:45:52 【问题描述】:

我通常使用PROC SQL 来加入一个也有日期条件的表(即target_date 介于start_dateend_date 之间)。

在考虑INNER JOIN 时,我已经能够成功地将其转换为哈希联接:

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;

不过,我很难弄清楚 LEFT JOIN 的等价物是什么。 例如,如果某些东西不是JOIN,我想输出,我认为这很简单:

if add1.find() ne 0 then output;

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

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_dateend_date 之间没有 target_date 的其余记录? 例如, 假设 table_2 是促销的 start_dateend_date,而 key_1 = 'Clothes' 的促销直到 2 月 1 日才开始。如果我的table_1 在 1 月 1 日有 '衣服' 和销售,它会在键上 JOIN,但我想输出空白值。关于如何做到这一点的任何想法?

任何帮助将不胜感激!

【问题讨论】:

【参考方案1】:

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

请参阅此示例。在这里,我修改 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;

【讨论】:

正如我的孩子们所说的,“JINX” 大声笑。是的,非常相似的代码,因为我们是分开做的......然后,将你的代码粘贴到我的上面,但使用我的示例数据可以正常工作。 实际上,它不是 100% 工作的......它肯定包括那些没有链接的,但它为其输入了错误的值(即日期和 value_1 值不匹配target_date),而不是所有空白的记录。 澄清一下:它从 table_1 返回初始值,并使用 found = 。但是,它还在输出中返回来自 table_2 的最后一个 value_1、start_date 和 end_date 值。所以找到 = .,但返回的值不正确。 call missing(of value_1); 在最后一个输出行之前。【参考方案2】:

我认为您只需要跟踪是否有键,但不在范围内:

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 中的编码。如果它不起作用,请告诉我。

【讨论】:

以上是关于之间的 PROC SQL 上的哈希连接等效项的主要内容,如果未能解决你的问题,请参考以下文章

SQL Server 2008 中嵌套循环连接和哈希连接的区别

蜂窝连接的 UIRequiresPersistentWiFi 等效项

SQL左反半连接等效查询

哈希完全外连接如何工作?

通过对两个日期之间的值求和来连接两个数据帧,sumif 等效

如何连接两个等效表,它们是 SQL Server 中先前递归选择的结果