Indexing SAS-Proc SQL或Merge-尝试优化包含字符串搜索(索引)的内部联接

Indexing SAS-Proc SQL或Merge-尝试优化包含字符串搜索(索引)的内部联接,indexing,sas,string-search,Indexing,Sas,String Search,我有一个基本的SAS技能集,其中大部分涉及“proc-sql”,因此可以自由地挑战使用此技能的基本方法 我正在尝试将一组个人详细信息与另一组进行匹配,第一组有大约40万行,另一组有2200万行。复杂的是,40万行包含以前的姓名和邮政编码以及当前的姓名和邮政编码(都在同一行),因此我的方法(下面的代码)是将所有的姓氏和邮政编码连接在一起,并从第二个表中搜索字符串(单个姓名和邮政编码)在使用index(source,extract)函数连接的字符串中 proc sql; CREATE TABLE R

我有一个基本的SAS技能集,其中大部分涉及“proc-sql”,因此可以自由地挑战使用此技能的基本方法

我正在尝试将一组个人详细信息与另一组进行匹配,第一组有大约40万行,另一组有2200万行。复杂的是,40万行包含以前的姓名和邮政编码以及当前的姓名和邮政编码(都在同一行),因此我的方法(下面的代码)是将所有的姓氏和邮政编码连接在一起,并从第二个表中搜索字符串(单个姓名和邮政编码)在使用index(source,extract)函数连接的字符串中

proc sql;
CREATE TABLE R4 AS
SELECT DISTINCT
BS.CUST_ID,
ED.MATCH_ID
FROM T_RECS_WITH_CONCATS BS
INNER JOIN T_RECS_TO_MATCH ED
ON LENGTH(ED.SinglePostcode) > 4
AND index(BS.AllSurnames,ED.SingleSurname) > 0
AND index(BS.AllPostcodes,ED.SinglePostcode) > 0
;
QUIT;
在上述情况下,所有姓氏最多可以包含9个姓氏(以|分隔),所有邮政编码最多可以包含9个串联邮政编码(同样,以|分隔)


当然,这样做的缺点是,它需要永远运行下去。在proc sql步骤或实际数据步骤中,是否有更有效的方法来执行此操作?

下面是一种使用哈希组件对象的方法

假设数据集被命名为短多和高一。使用SHORT\u MANY中的数据填充一个多数据哈希表,该哈希表可以作为在toll\u ONE中检查的值的查找

仅使用姓氏和邮政编码作为查找键可能会导致许多错误匹配

示例(带数字姓氏和邮政编码)

数据短\多;
do cust_id=1至400;
数组姓氏1-9;
阵列邮政编码邮政编码1-9;
(姓氏(*)呼叫缺失;
do索引=1到dim(姓氏);
姓氏(指数)=ceil(100000*Ranui(123));
邮政编码(索引)=ceil(99999*拉努尼(123));
如果ranuni(123)<0.15,则离开;
结束;
产出;
结束;
跑
数据高度(保留=匹配id姓氏邮编);
不匹配_id=1到22000;
姓氏=ceil(100000*Ranui(1234));
邮政编码=ceil(99999*拉努尼(1234));
forcemark=。;
如果ranuni(123)<0.15,则执行;*随机确保某些匹配将发生;
点=ceil(400*Ranui(123));
设置短\多点=点;
数组姓氏1-9;
阵列邮政编码邮政编码1-9;
直到(姓ne)为止;
指数=ceil(9*Ranui(123));
姓氏=姓氏(索引);
邮政编码=邮政编码(索引);
结束;
力标记=点;
结束;
产出;
结束;
停止
跑
高满足短时的数据(保持=客户id匹配id索引);
如果为0,则设置高\u一短\u多;*准备pdv(用于哈希主机变量);
如果_n_=1,则执行;
长度指数8;
声明哈希查找(多数据:“是”);
lookup.defineKey('姓氏','邮政编码');
lookup.defineData('cust_id','index');
lookup.defineDone();
do while(未填写);
设置短\多个端点=查找\填充;
数组姓氏1-9;
阵列邮政编码邮政编码1-9;
do索引=1到dim(姓氏),而(姓氏(索引)ne.);
姓氏=姓氏(索引);
邮政编码=邮政编码(索引);
lookup.add();
结束;
结束;
结束;
电话丢失(姓氏、邮政编码、客户id、索引);
高高的一个;
rc=查找。查找();*只抓取第一个匹配项——让_next/find_next检索其他查找匹配项;
跑

请向我们展示示例数据(前几行),以便我们重现您的尝试并更好地说明您的解释。这包括你想要的结果。听起来好像一张桌子是宽的,另一张是长的。考虑<代码> PROC转置在宽格式上长并加入/合并这两种长类型。您应该首先用多个记录简化表,特别是如果有日期和任何指示符,然后进行合并。您最终仍然需要这样做,因为您可能需要知道数据中的个人数量。
data SHORT_MANY;
  do cust_id = 1 to 400;
    array Surnames  surname1-surname9;
    array Postcodes postcode1-postcode9;

    call missing (of surnames(*));
    do index = 1 to dim(surnames);
      surnames(index)  = ceil (100000 * ranuni(123));
      postcodes(index) = ceil ( 99999 * ranuni(123));
      if ranuni(123) < 0.15 then leave;
    end;

    output;
  end;
run;

data TALL_ONE(keep=match_id surname postcode forcemark);
  do match_id = 1 to 22000;

    surname  = ceil(100000 * ranuni(1234));
    postcode = ceil( 99999 * ranuni(1234));
    forcemark = .;


    if ranuni(123) < 0.15 then do;  * randomly ensure some match will occur;
      point = ceil(400*ranuni(123));
      set SHORT_MANY point=point;
      array surnames surname1-surname9;
      array postcodes postcode1-postcode9;
      do until (surname ne .);
        index = ceil(9 * ranuni(123));
        surname = surnames(index);
        postcode = postcodes(index);
      end;
      forcemark = point;
    end;

    output;
  end;

  stop;
run;

data WHEN_TALL_MEETS_SHORT(keep=cust_id match_id index);

  if 0 then set TALL_ONE SHORT_MANY ; * prep pdv (for hash host variables);

  if _n_ = 1 then do;
    length index 8;

    declare hash lookup(multidata: 'yes');
    lookup.defineKey('surname', 'postcode');
    lookup.defineData('cust_id', 'index');
    lookup.defineDone();

    do while (not lookup_filled);
      SET SHORT_MANY end=lookup_filled;

      array Surnames  surname1-surname9;
      array Postcodes postcode1-postcode9;

      do index = 1 to dim(surnames) while (surnames(index) ne .);
        surname = surnames(index);
        postcode = postcodes(index);

        lookup.add();
      end; 
    end;
  end;

  call missing (surname, postcode, cust_id, index);

  set TALL_ONE;
  rc = lookup.find(); * grab just first match -- has_next/find_next to retrieve other lookup matches;
run;