2017-01-20 4 views
1

Это основано на ответе на вопрос here о том, как использовать SAS для решения следующей проблемы. [ПРИМЕЧАНИЕ. Существует рабочее шаговое решение SAS, но я просто пытался понять, как он будет работать в SQL.]Идеи для улучшения SQL-запроса SAS

Проблема (немного сложная для описания) - это посмотреть на каждую транзакцию для клиента, оглянитесь назад на 90 дней с даты этой транзакции, подсчитайте общее количество транзакций клиента в этом 90-дневном окне, сохраните этот номер с исходной транзакцией, подсчитайте количество различных менеджеров учетных записей, обрабатывающих транзакции клиента в этом 90-дневном окне, и сохранить это число с исходной транзакцией.

Вот шаг данных для инициализации набора данных теста транзакций и мой SAS SQL решение:

data transaction; 
    length customerid $ 12 accountmanager $7 transactionid $ 12; 
    input CustomerID AccountManager TransactionID Transaction_Time datetime.; 
    format transaction_time datetime.; 
    datalines; 
1111111111 FA001   TR2016001  08SEP16:11:19:25 
1111111111 FA001   TR2016002  26OCT16:08:22:49 
1111111111 FA002   TR2016003  04NOV16:08:05:36 
1111111111 FA003   TR2016004  04NOV16:17:15:52 
1111111111 FA004   TR2016005  25NOV16:13:04:16 
1231231234 FA005   TR2016006  25AUG15:08:03:29 
1231231234 FA005   TR2016007  16SEP15:08:24:24 
1231231234 FA008   TR2016008  18SEP15:14:42:29 
;;;; 
run; 

proc sql; 
    create table want as 
     select mgrs.*, trans.tranct 
     from 
      (select t3.customerid, t3.accountmanager, t3.transactionid, t3.transaction_time, count(*) as mgrct 
       from (select distinct t1.*, t2.accountmanager as m2 
         from transaction t1, transaction t2 
         where t1.customerid=t2.customerid 
          and 
          datepart(t1.transaction_time) >= datepart(t2.transaction_time)-90 
          and 
          t2.transaction_time <= t1.transaction_time) t3 
       group by t3.customerid, t3.accountmanager, t3.transactionid, t3.transaction_time) mgrs, 
      (select t4.customerid, t4.transactionid, count(*) as tranct 
       from transaction t4, transaction t5 
       where t4.customerid=t5.customerid 
         and 
         datepart(t4.transaction_time) >= datepart(t5.transaction_time)-90 
         and 
         t5.transaction_time <= t4.transaction_time 
       group by t4.customerid, t4.transactionid) trans 
     where mgrs.customerid=trans.customerid and mgrs.transactionid=trans.transactionid; 
quit; 

Результат выглядит следующим образом:

customerid accountmanager transactionid Transaction_Time mgrct tranct 
1111111111 FA001   TR2016001  08SEP16:11:19:25 1  1 
1111111111 FA001   TR2016002  26OCT16:08:22:49 1  2 
1111111111 FA002   TR2016003  04NOV16:08:05:36 2  3 
1111111111 FA003   TR2016004  04NOV16:17:15:52 3  4 
1111111111 FA004   TR2016005  25NOV16:13:04:16 4  5 
1231231234 FA005   TR2016006  25AUG15:08:03:29 1  1 
1231231234 FA005   TR2016007  16SEP15:08:24:24 1  2 
1231231234 FA008   TR2016008  18SEP15:14:42:29 2  3 

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

+0

Вы конкретно хотите работать в этом в SQL, или ты в порядке с шагом данные кода? Я согласен с тем, что, скорее всего, SQL будет более сложным, чем шаг данных для такого рода проблем. – Joe

+0

@Joe - Первоначальная проблема была чужой, и я предложил им решение для шага данных SAS. Мне было просто любопытно, как это работает в SQL, и это то, что я придумал. Так что теперь мне интересно, есть ли более элегантное SQL-решение. – vknowles

+0

И вы хотите, чтобы SAS SQL-решение специально, не так ли? Не тот, который будет работать в большинстве других SQL-вкусов, но не в базовом SAS (т. Е. С использованием оконных функций) ... – Joe

ответ

3

Думаю, вам просто нужно присоединиться к таблице с собой.

proc sql noprint ; 
create table want as 
    select a.* 
     , count(distinct b.accountmanager) as mgrct 
     , count(*) as tranct 
    from transaction a 
    left join transaction b 
    on a.customerid = b.customerid 
    and b.transaction_time <= a.transaction_time 
    and datepart(a.transaction_time)-datepart(b.transaction_time) 
     between 0 and 90 
    group by 1,2,3,4 
; 
quit; 

Результаты

1111111111 FA001 TR2016001 08SEP16:11:19:25 1 1 
1111111111 FA001 TR2016002 26OCT16:08:22:49 1 2 
1111111111 FA002 TR2016003 04NOV16:08:05:36 2 3 
1111111111 FA003 TR2016004 04NOV16:17:15:52 3 4 
1111111111 FA004 TR2016005 25NOV16:13:04:16 4 5 
1231231234 FA005 TR2016006 25AUG15:08:03:29 1 1 
1231231234 FA005 TR2016007 16SEP15:08:24:24 1 2 
1231231234 FA008 TR2016008 18SEP15:14:42:29 2 3 
+0

Спасибо, Том! То, что мне не хватало, было 'count (different b.accountmanager)' - мой запрос прошел повсюду, чтобы дублировать это. Кроме того, ваш запрос выполняется намного быстрее, по крайней мере, для тестового набора транзакций. – vknowles

+1

Не нужны средние критерии, если вы используете 0-90, используя intck вместо datepart. – Joe

+0

Оглядываясь назад, я удивляюсь, почему вы использовали левое соединение. Кажется, что он работает с регулярным внутренним соединением, потому что транзакция «фокуса» всегда совпадает сама по себе - всегда есть хотя бы одна строка, возвращаемая из «a» и «b». – vknowles