2014-12-06 54 views
1

我試圖在事實之後從數據庫的事務表中創建定期快照視圖。交易表具有以下字段:SQL從事務中生成定期快照表

  • ACCOUNT_ID(外鍵)
  • EVENT_ID
  • status_dt
  • status_cd

每次帳戶改變了應用程序的狀態,新的行以新狀態添加到交易表中。我想創建一個視圖,顯示每個日期的狀態帳戶數量;它應該具有以下字段:

  • snapshot_dt
  • status_cd
  • count_of_accounts

這將讓任何給定的一天計數,但不是所有的日子:

SELECT status_cd, COUNT(account_id) AS count_of_accounts 
FROM transactions 
JOIN (
     SELECT account_id, MAX(event_id) AS event_id 
     FROM transactions 
     WHERE status_dt <= DATE '2014-12-05') latest 
USING (account_id, event_id) 
GROUP BY status_cd 

謝謝!

+0

你使用了哪個數據庫?我會猜測Oracle,但你應該明確問題上的標籤。 – 2014-12-06 01:46:05

+0

是的Oracle。謝謝你的提示!我主要發現將專有擴展從一個SQL轉換爲另一個並不困難,但不必非要。 – Jared 2014-12-07 17:22:07

回答

0

好的,這將很難解釋。

在每個日期對應每種狀態,你應該算兩個值:

  • 誰與狀態開始客戶的數量。
  • 以此狀態離開的客戶數量。

第一個值很簡單。它只是按日期和狀態彙總交易。

第二個值幾乎一樣容易。您將獲得之前的狀態碼,並計算該狀態碼在該日期「離開」的次數。

然後,關鍵是第一個值的累加和減去第二個值的累加和。

我坦率地承認,下面的代碼沒有經過測試(如果你有一個SQL小提琴,我很樂意測試它)。但是,這是生成的查詢是什麼樣子:

select status_dte, status_cd, 
     (sum(inc_cnt) over (partition by status_cd order by status_dt) - 
     sum(dec_cnt) over (partition by status_cd order by status_dt) 
     ) as dateamount 
from ((select t.status_dt, t.status_cd, count(*) as inc_cnt, 0 as dec_cnt 
     from transactions t 
     group by t.status_dt, t.status_cd 
    ) union all 
     (select t.status_dt, prev_status_cd, 0, count(*) 
     from (select t.* 
        lag(t.status_cd) over (partition by t.account_id order by status_dt) as prev_status_cd 
      from transactions t 
      ) t 
     where prev_status_cd is null 
     group by t.status_dt, prev_status_cd 
    ) 
    ) t; 

如果您有日期,其中有一個或多個狀態要包括那些在輸出沒有變化,那麼上面的查詢需要使用cross join首先在結果集中創建行。目前尚不清楚這是否是一項要求,所以我將這一併發症排除在外。

+0

太棒了,非常感謝!在你的代碼中有一個錯字(應該是'prev_status_cd是**不是** null'),但除此之外它效果很好。 – Jared 2014-12-08 19:28:55

+0

我想快照沒有狀態變化的日期。有沒有比這更優雅的方式: 'SELECT DISTINCT status_dte, status_cd, (SUM(inc_cnt)OVER(PARTITION BY status_cd ORDER BY status_dte) - SUM(dec_cnt)OVER(PARTITION BY status_cd ORDER BY status_dte ))AS dateamount FROM(( SELECT status_dte,status_cd,0 AS inc_cnt,0 AS dec_cnt FROM( SELECT DISTINCT status_cd FROM交易) CROSS JOIN( SELECT DISTINCT status_dte FROM交易)) UNION ALL( ...' – Jared 2014-12-08 19:31:21