递归添加到SAS中的数据table

Recursively add to a data table in SAS

我是 SAS 新手。我需要进行 x- 次迭代来填充名为 MYRS.

的数据集

每次迭代需要JOIN TABLE1 with (TABLE2+ MYRS) MINUS MYRS table 中已有的记录。

然后,我需要用额外的匹配更新 MYRS table。目标是跟踪一系列电子邮件。

MYRS 本质上是 TABLE1 的副本并包含匹配记录。有点棘手。 (简化模式)。 Table1 可以有 DUPS。

例如

TABLE1:
ID | EMAIL1 | EMAIL2 | EMAIL3 | EMAIL4|
1 | A | s | d | F
2 | g | F | j | L
3 | z | x | L | v
4 | z | x | L | v
2 | g | F | j | L

TABLE2:
EMAIL
A

MYRS (starts as empty dataset)
EMAIL1 | EMAIL2 | EMAIL3 | EMAIL4

逻辑:TABLE1 的电子邮件与 TABLE2 中的电子邮件匹配。因此需要显示此记录。其他记录与 TABLE2 中的任何内容都不匹配。但是因为Record1Record2共享the same ALTERNATIVE emailF,所以也需要显示Record2。但是因为 Record2Record3 共享相同的替代电子邮件 L,所以 Record3 也需要显示。所以第四...

proc sql;        
SELECT TABLE1.id,
    TABLE1.email1,
    TABLE1.email2,
    TABLE1.email3,
    TABLE1.email4
FROM TABLE1
INNER JOIN (
    SELECT EMAIL
    FROM TABLE2     
     UNION      
    SELECT EMAIL1 AS EMAIL
    FROM MYRS   
     UNION      
    SELECT EMAIL2 AS EMAIL
    FROM MYRS   
     UNION      
    SELECT EMAIL3 AS EMAIL
    FROM MYRS   
     UNION      
    SELECT EMAIL4 AS EMAIL
    FROM MYRS
    )
ON EMAIL=EMAIL1 OR EMAIL=EMAIL2 OR EMAIL=EMAIL3 OR EMAIL=EMAIL4
WHERE TABLE1.id NOT IN (
        SELECT DISTINCT ID
        FROM MYRS
        )
quit;

如何创建以下逻辑:

  1. 将其包装成某种函数
  2. 在sql执行之前,计算MYDS中的记录数量并保存计数
  3. 执行SQL并更新MYDS
  4. 计算 MYDS 中的记录数量
  5. 如果MYDS计数没有变化,停止执行
  6. 否则,转到#3

我是 SAS 的新手(准确地说是 3 天),正在尝试将所有内容放在一起。 (如果我要在 Java 中这样做,我会使用上面的逻辑)

这是一个宏方法,它主要遵循您的逻辑,但首先转换您的数据,input/output 是一个 ID 的列表(您可以使用它轻松地收发电子邮件) .

这段代码可能会介绍很多您不熟悉的 SAS 功能,但下面的评论和解释应该有所帮助。如果仍有任何不清楚的地方,请查看链接或添加评论。

它需要输入数据:

  • inData:带有 IDEMAIL* 变量的 TABLE1
  • matched:已知通缉名单IDs

它returns:

  • matched:更新的通缉名单 IDs

/* Wrap the processing in a macro so that we can use a %do loop */
%macro looper(maxIter = 5);
    /* Put all the emails in one column to make comparison simpler */
    proc transpose data = inData out = trans (rename = (col1 = email));
        by ID;
        var email:;
    run;        
    /* Initialise the counts for the %where condition */
    %let _nMatched = 0;
    %let nMatched = 1;
    %let i = 0;
    /* Loop until no new IDs are added (or maximum number of iterations) */
    %do %while(&_nMatched. < &nMatched. and &i < &maxIter.); 
        %let _nMatched = &nMatched.;
        %let i = %eval(&i. + 1);
        %put NOTE: Loop &i.: &nMatched. matched.;
        /* Move matches to a temporary table */
        proc datasets library = work nolist nowarn;
            delete _matched;
            change matched = _matched;
        quit;
        /* Get new matched IDs */
        proc sql noprint;
            create table matched as
            select distinct c.ID
            from _matched as a
            left join trans as b
                on a.ID = b.ID
            left join trans as c
                on b.email = c.email;
            /* Get new count */
            select count(*) into :nMatched from matched;
        quit;
    %end;
%mend looper;
%looper(maxIter = 10);

有趣的部分是:

  • proc transpose:将输入转换为深度 table 以便所有电子邮件地址都在一个变量中,这使得编写电子邮件比较逻辑更简单(需要更少的重复)并将数据放入采用一种格式,以便您在必要时更轻松地清理电子邮件地址(想想 upcase()strip() 等)。
  • %macro %mend:用于定义macro的语句。这是必要的,因为您不能在开放代码中使用宏逻辑或循环。我还添加了一个参数,以便您了解它是如何工作的。
  • %let and select into :: Two ways to create macro variables。宏变量用前缀 & 引用,用于在执行前将文本插入 SAS 程序。
  • %do %while() %end:在宏内执行循环的方法之一。其中的代码将重复 运行,直到条件计算结果为 false。
  • proc datasets:对数据集和库执行管理任务的过程。此处用于删除和重命名临时 tables.