Sas 如果在24小时内有另一个观测值,请选择该观测值

Sas 如果在24小时内有另一个观测值,请选择该观测值,sas,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

我正在尝试创建一个表,该表仅填充一个联系人的条目到一个客户的业务号码,如果他们在尝试使用业务号码之前的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小时内有多个观测值的计数。

我相信我已经找到了答案

我有HAVEA和HAVEB表,分别承载H型和B型条目

然后我运行了下面的procsql

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;
请让我知道,对于较大的数据量,这是否是一个可持续的答案,或者是否有更好的方法来解决这一问题。

因此,这会起作用,但对于大量的数字来说会非常混乱-因为您在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;
请注意:

我使用道琼斯指数循环,但这并不是强制性的,我只是喜欢从清晰的角度来看,它清楚地表明我在重复做一些事情。您可以删除该循环,并为最后一个家庭添加保留,它将是相同的。 我使用INTCK而不是INTNX-同样为了清晰起见,您的INTNX也很好,但是INTCK只是进行比较,而INTNX用于将日期提前一段时间。我使用了一个匹配我正在尝试做的,所以阅读代码的人可以很容易地看到我在做什么。
在更大的数据集上,如果没有其他原因,这将比SQL快得多,因为它只传递一次数据。SQL必须多次执行此操作,即使您没有在SQL查询中分离HAVEA/HAVEB

执行选择以获得最终结果集,而无需创建中间表。这里有两种选择:

第一条路

类似于你的“弄明白”。在过去24小时86400秒内未发生的to_业务呼叫之前,使用分组的反射连接检测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
       ;
第二条路

对24小时前的到家电话和每次的业务电话进行非存在性检查

  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
    )
  ;

散列解决方案确实对数据量和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;

这太烦人了,现在我明白了,这是完全有道理的,但我一辈子都不能自己去想。在执行此数据步骤之前,主要需要确保数据位于单个表中,并按ID排序,然后按记录排序,对吗?对。您可以通过将该记录添加到by语句来强制执行该记录,而不会产生任何实际问题。它实际上不必在一个数据集中,如果它在两个HAVEA和HAVEB中,通过合并,或者跨多天的多个数据集中,只需将它们添加到SET语句中,就可以执行类似的操作。