选择一个观测值,如果它在24小时内还有另一个观测值

时间:2019-04-19 15:53:20

标签: sas

我正在尝试创建一个表,该表仅在未尝试使用该公司电话号码的24小时之内未首先通过家庭电话联系他们的情况下,才使用该公司电话号码填充与客户的联系条目。

如果我有

DATA HAVE;
 INPUT ID RECORD DATETIME. TYPE;
 FORMAT RECORD DATETIME.;
 CARDS;
 1 17MAY2018:06:24:28 H
 1 18MAY2018:05:24:28 B
 1 20MAY2018:06:24:28 B
 2 20MAY2018:07:24:28 H
 2 20MAY2018:08:24:28 B
 2 22MAY2018:06:24:28 H
 2 24MAY2018:06:24:28 B
 3 25MAY2018:06:24:28 H
 3 25MAY2018:07:24:28 B
 3 25MAY2018:08:24:28 B
 4 26MAY2018:06:24:28 H
 4 26MAY2018:07:24:28 B
 4 27MAY2018:08:24:28 H
 4 27MAY2018:09:24:28 B
 5 28MAY2018:06:24:28 H
 5 29MAY2018:07:24:28 B
 5 29MAY2018:08:24:28 B
 ;
RUN;

我希望能够得到

1 20MAY2018:06:24:28 B
2 24MAY2018:06:24:28 B
5 29MAY2018:07:24:28 B
5 29MAY2018:08:24:28 B

我尝试将计数添加到ID中,但是我不确定如何使用它,或者是否有办法在proc sql中使用子查询来创建计数超过每24小时一次。

4 个答案:

答案 0 :(得分:1)

因此,your approach可以工作,但是相当会有很多混乱-因为您在ID中进行笛卡尔联接。如果每个ID都有很少的记录,那还不错,但是如果每个ID都有很多记录,那么您将建立很多连接。

幸运的是,在SAS中有一种简单的方法!

data want;
  do _n_ = 1 by 1 until (last.id);  *for each ID:;
    set have;
    by id;    
    if first.id then last_home=0;   *initialize last_home to 0;
    if type='H' then last_home = record;  *if it is a home then save it aside;
    if type='B' and intck('Hour',last_home,record,'c') gt 24 then output;   *if it is business then check if 24 hours have passed;
  end;
  format last_home datetime.;
run;

一些注意事项:

  • 我使用DoW循环,但这并不是强制性的,从清晰度的角度来看,我只是喜欢它(这清楚地表明我正在执行ID重复级别的操作)。您可以删除该循环,并为last_home添加一个RETAIN,它会是相同的。
  • 我使用INTCK而不是INTNX-再次为了清楚起见,您的INTNX也很好,但是INTCK只是进行比较,而INTNX则是提前日期。我使用的是与我要执行的操作匹配的代码,因此阅读代码的人可以轻松了解我在做什么。

如果没有其他原因(仅传递一次数据),这将比大型数据集上的SQL快得多。即使您没有将HAVEA / HAVEB分开并在SQL查询中执行,SQL也会多次执行此操作。

答案 1 :(得分:0)

我相信我知道了!

我有分别托管H型和B型条目的HAVEA和HAVEB表。

然后我运行了以下PROC SQL。

PROC SQL;
CREATE TABLE WANTA AS
SELECT A.RECORD AS PREVIOUS_CALL, B.* FROM HAVEB B
JOIN HAVEA A ON (B.ID=A.ID AND A.RECORD LE B.RECORD);

CREATE TABLE WANTB AS
SELECT * FROM WANTA
GROUP BY ID, RECORD
HAVING PREVIOUS_CALL = MAX(PREVIOUS_CALL);

CREATE TABLE WANTC AS
SELECT * FROM WANTB
WHERE INTNX('HOUR',RECORD,-24,'SAME') GT PREVIOUS_CALL;
QUIT;

请问这是否不是对大量数据的可持续解决方案,或者是否有更好的方法来解决这一问题。

答案 2 :(得分:0)

您无需执行中间表即可执行选择以获得最终结果集。这里有两种选择:

第一种方式

类似于您的“设计”。具有分组功能的自反连接在过去24小时(86,400秒)内未发生的“ to_business”呼叫之前检测到“ to_home”呼叫

proc sql;
  create table want as
  select distinct
    business.*
  from have as business
  join have as home
    on business.id = home.id
       & business.type = 'B'
       & home.type = 'H'
       & home.CALL_DT < business.CALL_DT
   group by
     business.call_dt
   having
     max(home.call_dt) < business.call_dt - 86400
       ;

第二种方式

对于每个to_business调用,在之前的24小时内对to_home调用执行NOT存在检查。

  create table want2 as
  select 
    business.*
  from
    have as business
  where
    business.type = 'B'
    and
    not exists (
      select * from have as home
      where home.id = business.id
        and home.type = 'H'
        and home.call_dt < business.call_dt
        and home.call_dt >= business.call_dt - 86400
    )
  ;

答案 3 :(得分:0)

HASH解决方案确实具有某些依赖性(数据和RAM量)...但这是另一种选择

DATA HAVE;
 INPUT ID RECORD DATETIME. TYPE $;
 FORMAT RECORD DATETIME.;
 CARDS;
 1 17MAY2018:06:24:28 H
 1 18MAY2018:05:24:28 B
 1 20MAY2018:06:24:28 B
 2 20MAY2018:07:24:28 H
 2 20MAY2018:08:24:28 B
 2 22MAY2018:06:24:28 H
 2 24MAY2018:06:24:28 B
 3 25MAY2018:06:24:28 H
 3 25MAY2018:07:24:28 B
 3 25MAY2018:08:24:28 B
 4 26MAY2018:06:24:28 H
 4 26MAY2018:07:24:28 B
 4 27MAY2018:08:24:28 H
 4 27MAY2018:09:24:28 B
 5 28MAY2018:06:24:28 H
 5 29MAY2018:07:24:28 B
 5 29MAY2018:08:24:28 B
 ;
RUN;

 /* Keep only HOME TYPE records and 
     rename RECORD for using in comparision */
Data HOME(Keep=ID RECORD rename=(record=hrecord));
 Set HAVE(where=(Type="H"));
Run;

Data WANT(Keep=ID RECORD TYPE);
   /* Use only BUSINESS TYPE records */
 Set HAVE(where=(Type="B"));

  /* Set up HASH object */    
 If _N_=1 Then Do;
   /* Multidata:YES for looping through 
       all successful FINDs */
  Declare HASH HOME(dataset:"HOME", multidata:'yes');
  home.DEFINEKEY('id');
  home.DEFINEDATA('hrecord');
  home.DEFINEDONE();
   /* To prevent warnings in the log */
  Call Missing(HRECORD);
 End;

   /* FIND first KEY match */
 rc=home.FIND();
   /* Successful FINDs result in RC=0 */
 Do While (RC=0);
   /* This will keep the result of the most recent, in datetime,
       HOME/BUS record comparision */
   If intck('Hour',hrecord,record,'c') > 24 Then Good_For_Output=1;
   Else Good_For_Output=0;
    /* Keep comparing HOME/BUS for all HOME records */
   rc=home.FIND_NEXT();
 End;

 If Good_For_Output=1 Then Output;
Run;