2017-01-20 6 views
1

これは、SASを使用して以下の問題を解決する方法について私がhereと回答した質問に基づいています。 [注記:SASデータステップの解決策がありますが、SQLでどのように動作するかを確認しようとしていました]SAS SQLクエリを改善するアイデア

問題は(説明するのは少し難しい)そのトランザクションの日付から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(distinct b.accountmanager)'でした。 - 私のクエリは、それを複製するために全面的に行きました。また、少なくともテストセットのトランザクションでは、クエリははるかに高速です。 – vknowles

+1

datepartの代わりにintckを使用して0-90を実装する場合は、中間基準は必要ありません。 – Joe

+0

これを振り返って、左結合を使った理由は不思議です。トランザクションの "焦点"は常にそれ自身と一致するため、通常の内部結合で動作するようです。常に "a"と "b"から返される行が少なくとも1つあります。 – vknowles

関連する問題