1

アクティビティを示すフィールドとともに、月ごとのアカウントのリストを含むテーブルがあります。次の基準に基づいて、アカウントがいつ「死亡」したかを検索したいと考えています。

  1. アカウントは、連続した月間、一貫したアクティビティを持っていました
  2. 最終月にアカウントのアクティビティが急増した (スパイク = 過去の連続するすべての月のアクティビティの平均の 200% 以上)
  3. アクティビティが急増した直後の月と次の 12 か月はす​​べてアクティビティがありませんでした

したがって、テーブルは次のようになります。

ID | Date      | Activity
1  | 1/1/2010  | 2
2  | 1/1/2010  | 3.2
1  | 2/3/2010  | 3
2  | 2/3/2010  | 2.7
1  | 3/2/2010  | 8
2  | 3/2/2010  | 9
1  | 4/6/2010  | 0
2  | 4/6/2010  | 0
1  | 5/2/2010  | 0
2  | 5/2/2010  | 2

したがって、この場合、アカウント 1 と 2 の両方が 1 月から 3 月に活動しています。どちらのアカウントも 3 月に活動が急増しています。どちらのアカウントも 4 月のアクティビティはありません。アカウント 2 は 5 月に再び活動がありますが、アカウント 1 は活動していません。したがって、私のクエリはアカウント 1 を返しますが、アカウント 2 は返しません。これをクエリ結果として表示したいと思います。

ID | Last Date
1  | 3/2/2010 

これは複雑な質問であり、誰かが私のためにクエリ全体を書いてくれるとは思っていません。私が考えることができる現在の最善のアプローチは、一連のサブクエリを作成して結合することですが、サブクエリがどのようになるかさえわかりません。例: アクティビティがすべて 0 (またはすべてゼロ以外) である単一 ID の連続した一連の行を探すにはどうすればよいですか?

SQL が単純に複雑すぎる場合の私のフォールバックは、Java を使用してブルート フォース検索を使用することです。最初にすべての一意の ID を見つけてから、一意の ID ごとに月間で繰り返し、ID が「死んだ」かどうか、いつ死んだかを判断します。 .

繰り返しますが、正しい方向に進むための助けをいただければ幸いです。

4

2 に答える 2

0

おそらく世界で最も効率的なコードではありませんが、これはあなたが求めていることを行うと思います:

declare @t table (AccountId int, ActivityDate date, Activity float)

insert @t 
      select 1,   '2010-01-01', 2
union select 2,   '2010-01-01', 3.2
union select 1,   '2010-02-03', 3
union select 2,   '2010-02-03', 2.7
union select 1,   '2010-03-02', 8
union select 2,   '2010-03-02', 9
union select 1,   '2010-04-06', 0
union select 2,   '2010-04-06', 0
union select 1,   '2010-05-02', 0
union select 2,   '2010-05-02', 2


select AccountId, ActivityDate LastActivityDate --, Activity
from @t a
where 
--Part 2 --select only where the activity is a peak
Activity >= isnull
(
    (
        select 2 * avg(c.Activity)
        from @t c
        where c.AccountId = 1
        and c.ActivityDate >= isnull
        (
            (
                select max(d.ActivityDate)
                from @t d
                where d.AccountId = c.AccountId
                and d.ActivityDate < c.ActivityDate
                and d.Activity = 0  
            )
            ,
            (
                select min(e.ActivityDate)
                from @t e
                where e.AccountId = c.AccountId
            )
        )
        and c.ActivityDate < a.ActivityDate
    )
    , Activity + 1 --Part 1 (i.e. if no activity before today don't include the result)
)
--Part 3
and not exists --select only dates which have had no activity for the following 12 months on the same account (assumption: count no record as no activity / also ignore current date in this assumption)
(
    select 1
    from @t b
    where a.AccountId = b.AccountId
    and b.Activity > 0
    and b.ActivityDate between dateadd(DAY, 1, a.ActivityDate) and dateadd(YEAR, 1, a.ActivityDate)
)
于 2012-10-25T19:48:03.470 に答える
0

Java で処理するか、SQL で部分的に処理し、Java で処理を終了することは良い方法です。

スパイクを定義する方法に取り組むつもりはありません。

条件 3 から始めることをお勧めします。最後のゼロ以外の値を見つけるのは簡単です。次に、それがスパイクについてテストしたいものであり、スパイク前の一貫したデータです。

SELECT out.*
FROM monthly_activity out
  LEFT OUTER JOIN monthly_activity comp
    ON out.ID = comp.ID AND out.Date < comp.Date AND comp.Activity <> 0
WHERE comp.Date IS NULL

悪くはありませんが、レコードがその月の最後であるため、結果が必要ない場合は、代わりに、

SELECT out.*
FROM monthly_activity out
  INNER JOIN monthly_activity comp
    ON out.ID = comp.ID AND out.Date < comp.Date AND comp.Activity == 0
GROUP BY out.ID
于 2012-10-25T19:17:13.817 に答える