2012-10-25 82 views
1

我有一張表,其中包含月份的帳戶列表以及指示活動的字段。我想通過搜索發現,當一個帳戶已「死亡」,基於以下標準:涉及搜索連續日期的複雜查詢(按月)

  1. 帳戶有一致的活動了幾個月的連續週期
  2. 帳戶有活動的尖峯上最後一個月(穗= 200%以上的平均活動的所有先前連續幾個月)
  3. 月立即活動的扣球和未來12個月以下卻都0活動

所以該表可能看起來像這樣:

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月都會出現活躍的上漲。這兩個賬戶在四月份都有0個活動。賬戶2在5月再次有活動,但賬戶1沒有。因此,我的查詢應該返回賬戶1,但不佔2。我希望看到這是我的查詢結果:

ID | Last Date 
1 | 3/2/2010 

我意識到這是一個複雜的問題,我不期待任何人寫全爲我查詢。我能想到的當前最好的方法是創建一系列子查詢並加入它們,但我甚至不知道子查詢是什麼樣的。例如:如何查找活動全部爲0(或全部非零?)的單個ID的連續系列行。

如果SQL過於牽扯過,那麼我的回退就是使用使用Java的蠻力搜索,首先找到所有唯一ID,然後針對每個唯一ID在幾個月內迭代以確定是否以及何時ID「死亡」。

再一次:任何幫助向正確的方向移動非常讚賞。

+0

爲什麼應該考慮返回1,如果按照你的標準#3,那就需要秒殺(*'在一個月後顯示了13個月閒置緊隨其後活動的飆升未來12個月*)在宣佈死亡之前?或者您的描述中有錯誤嗎? –

+0

你使用什麼數據庫? –

+0

Andriy - 我只是不想輸入12個月的0。爲了爭辯,假設還有12個月,而且賬戶1對於所有人都是0。對不起,我很困惑(12個月是我現實生活中的標準,表格代表了一個可以讓這個概念跨越的嬰兒示例。) Gordon- 我將使用Talend整合來自多個來源的數據。這個特定的查詢將在Teradata數據庫上運行(我以後也會在DB2中進行鏈接。) –

回答

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 
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) 
) 
+0

John- 這段代碼看起來非常有前途,但是我必須先研究它,然後才能弄明白。非常感謝:如果我能將這一切全部保存在SQL中將大大簡化這個過程。 –

+0

不用擔心,如果任何事情沒有意義,請隨時給我發問。 – JohnLBevan