SAS / SQL - 在给定的时间范围内找到3个或更多个出现

时间:2017-03-13 12:11:48

标签: sql date sas proc-sql datastep

我有数十万行数据(如下例所示),其中包括帐号和已拨打的电话日期。我需要查找7天内有3个或更多电话的所有帐户。因此,对于下面的数据,它将返回帐户1111111和3333333的行。

account_number  call_date
1111111          1/1/2010
1111111          1/3/2010
1111111          1/3/2010
1111111          1/5/2010
2222222          1/10/2010
2222222          1/20/2010
3333333          1/7/2010
3333333          1/7/2010
3333333          1/7/2010

可能有一个简单的解决方案,但出于某种原因,我正在画一个空白。任何帮助将不胜感激。

4 个答案:

答案 0 :(得分:1)

以下是使用data steplag函数以及by group的替代答案。

proc sort data=have;
by acc_nbr call_date;
run;

data want(drop=count);
set have;
by acc_nbr call_date;
d2 = lag2(call_date);
format d2 date9.;
if first.acc_nbr then count = 1;
if count < 3 then d2 = .;
count + 1;
diff = call_date - d2;
if diff <= 7 and diff ne . then output;
run;

所有这一切都是使用lag2函数,该函数从当前记录之前的两个记录返回call_date的值。接下来,我们会说它是否是第一个帐号,然后设置count = 1。接下来,如果计数小于3,我们会将值d2设置为缺失。这可确保我们不会从单独的by group中选择日期值。最后,我们只是检查以确保call_dated2之间的差异小于或等于7并输出该记录。

如果客户在7天内多次拨打3次以上的电话,则会输出重复的帐号。如果您想要唯一值,则可以使用proc sql, select distinctproc sort nodupkey

答案 1 :(得分:1)

有趣的问题。以下是我认为我会做的事情:

输入数据。对于每个call_date,请计算7天前的日期。

data have;
    input account_number : $char20.
          call_date : mmddyy10.;
    date_7_days_before = intnx('DAY',call_date,-7);

datalines;
1111111 1/1/2010
1111111 1/3/2010
1111111 1/3/2010
1111111 1/5/2010
2222222 1/10/2010
2222222 1/20/2010
3333333 1/7/2010
3333333 1/7/2010
3333333 1/7/2010
;
run;

整合日内电话。每个帐户按天计算的电话总数。

proc sql;
    create table consolidate_calls as
    select account_number,
           call_date,
           date_7_days_before,
           count(*) as calls
   from have
   group by account_number,
            call_date,
            date_7_days_before;
quit;

自我加入consolidated_calls如果b.call_date位于a.date_7_days_beforea.call_date的日期范围内,则将其组合在一起。

proc sql;
    create table want as
    select a.account_number,
           a.call_date format=mmddyy10.,
           a.calls as calls_that_day,
           sum(b.calls) as calls_last_7_days /*Number of calls on, or within 7 days of, the call_date*/
    from consolidate_calls as a
    left join consolidate_calls as b
    on a.account_number = b.account_number
    and b.call_date <= a.call_date 
    and b.call_date >= a.date_7_days_before
    group by a.account_number,
             a.call_date,
             a.calls
    ;
quit;

自我加入方法对我来说有点难以解释,但我相信这应该有用。

答案 2 :(得分:0)

试试这个,看起来解决方案可以正确生成结果。

准备数据

data a;
    input account_number call_date :mmddyy.;
    format call_date ddmmyy10.;
datalines;
1 1/1/2010
1 1/3/2010
1 1/3/2010
1 1/5/2010
2 1/10/2010
2 1/20/2010
3 1/7/2010
3 1/7/2010
3 1/7/2010
;
run;

<强>解决方案

proc sql;
    select distinct a1.account_number
    from a a1, a a2, a a3
    where a1.account_number = a2.account_number 
        and a1.account_number = a3.account_number
        and a3.call_date > a2.call_date 
        and a2.call_date > a1.call_date 
        and a3.call_date < a1.call_date + 7;
quit;

答案 3 :(得分:0)

与@ J_Lard的方法类似,您可以使用DIF函数计算变量与其滞后之间的差异。这简化了代码。如果帐号是数字,您可以通过测试dif2(id)=0 and dif2(calldate)<=7找到感兴趣的记录。它检查ID是否与之前的两个记录相同,并且该校准在7天内。如果帐号不是数字,可以使用id=lag2(id) and dif2(calldate)<=7。当然,这假设数据已经被分类。

下面的代码添加了_DONE布尔值,用于跟踪是否已输出ID。

data want (keep=id);
  set have;
  by id;
  retain _done; *boolean to flag when an id has already been output;
  if first.id then _done=0;

  if _done=0 and dif2(id)=0 and dif2(calldate) <= 7 then do;
    output;
    _done=1;
  end;
run;