Выберите наблюдение, если оно имеет другое в течение 24 часов - PullRequest
3 голосов
/ 19 апреля 2019

Я пытаюсь создать таблицу, которая заполняет записи контакта с клиентом по служебному номеру, только если с ним НЕ связывались по домашнему номеру в течение 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

Я попытался добавить счетчик к идентификатору, но я не уверен, как бы япродолжайте использовать это, или если есть способ использовать подзапрос в proc sql для создания количества наблюдений, которые имеют более одного наблюдения за 24-часовой период.

Ответы [ 4 ]

1 голос
/ 19 апреля 2019

Итак, ваш подход сработает, но будет довольно запутаться с большими числами - так как вы делаете декартово объединение внутри 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, но это на самом деле не является обязательным, мне просто нравится это с точки зрения ясности (это дает понять, что я делаю что-то с идентификаторомуровень повторения).Вы можете удалить этот цикл и добавить RETAIN для last_home, и он будет таким же.
  • Я использую INTCK вместо INTNX - опять же, для ясности, ваш INTNX тоже подойдет, но INTCK просто выполняет сравнение,в то время как INTNX для опережающих дат на сумму.Я использую тот, который соответствует тому, что я пытаюсь сделать, так что кто-то, читающий код, может легко увидеть, что я делаю.

Это будет намного быстрее, чем SQL в больших наборах данных, если нетдругая причина, чем он передает данные только один раз.SQL обязательно сделает это несколько раз, даже если вы не разделяете HAVEA / HAVEB и делаете это в запросе SQL.

0 голосов
/ 21 апреля 2019

Решение HASH имеет некоторые зависимости (объем данных и ОЗУ) ... но это еще одна альтернатива

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;
0 голосов
/ 20 апреля 2019

Вы делаете выбор, чтобы получить окончательный набор результатов без создания промежуточных таблиц. Вот две альтернативы:

Первый путь

Похоже на ваше "выяснение этого". Рефлексивное соединение с группировкой обнаруживает вызовы "to_home" до вызовов "to_business", которые НЕ происходили в последние 24 часа (86 400 секунд)

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_home в предыдущие 24 часа для каждого вызова to_business.

  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
    )
  ;
0 голосов
/ 19 апреля 2019

Мне кажется, я понял это!

У меня есть таблицы HAVEA и HAVEB, содержащие записи типа H и типа B. соответственно.

Затем я запустил следующие 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;

Пожалуйста, дайте мне знать, если это не является устойчивым ответом для больших сумм данных или если есть гораздо лучший способ приблизиться к этому.

...