2016-06-14 76 views
1

我有這樣蜂巢:選擇以前的第n行與最低值的列

ID START_DATE STATUS 
10 2013-05-29 FREE 
10 2013-05-29 PAID 
10 2014-05-30 PAID 
10 2014-11-29 FREE 
10 2014-12-02 PAID 
10 2015-09-29 PAID 
10 2015-12-02 PAID 
10 2016-04-04 PAID 
10 2016-04-05 FREE 

數據我的輸出應該只包含行,其中狀態=「FREE」。每次狀態都是免費時,我需要獲取狀態=「已付費」的前一個最短日期。

ID STATUS PREVIOUS_MIN_PAID_START_DATE 
10 FREE NULL 
10 FREE 2013-05-29 
10 FREE 2014-12-02 

LAG()功能只給出了第一個前值,我怎麼能得到以前的最低(第n個)的價值?

SELECT 
    ID, 
    STATUS, 
    LAG(CASE WHEN STATUS = 'PAID' THEN START_DATE, 1) 
    OVER (PARTITION BY ID ORDER BY START_DATE) AS previous_paid_start_date 
FROM 
    TEMP 
WHERE 
    STATUS = 'FREE' 
+0

希望的輸出是不明確的。爲什麼只有三排?並且start_date列不存在,所以不清楚哪些輸出行對應於哪些輸入行。 – leftjoin

+0

我已更新所需的輸出消息。我想從之前的連續「付費」狀態中獲取以前的最小開始日期。希望有人能幫助我。 – pshan99

+0

兩條第一條記錄的日期相同。順序依賴於STATUS以及START_DATE嗎?還是它是示例數據中的錯誤? – leftjoin

回答

0

不知道爲什麼你收到downvotes,我認爲這是一個非常有趣的(和很好描述的問題)。無論如何,這裏是一種方式要做到這一點,但我必須承認它感覺不到最佳和hacky。

基本上,你需要什麼,直到你到達下一個FREE(我希望我已經正確地理解這一點),創建了一批「當前」 FREE和所有後續PAID的索引。爲了說明:

id start_date status idx 
10 2013-05-29 FREE 0 
10 2013-05-29 PAID 1 
10 2014-05-30 PAID 1 
10 2014-11-29 FREE 1 
10 2014-12-02 PAID 2 
10 2015-09-29 PAID 2 
10 2015-12-02 PAID 2 
10 2016-04-04 PAID 2 
10 2016-04-05 FREE 2 

然後從那裏你可以得到最小的起始日期,其中狀態爲PAID在ID的窗口和新創建的索引。

查詢

WITH tmp_table AS (
    SELECT * 
    , SUM(flg) OVER (PARTITION BY id ROWS UNBOUNDED PRECEDING) AS s 
    FROM (
    SELECT * 
     , LEAD(CASE WHEN status='FREE' THEN 1 ELSE 0 END, 1, 0) OVER (PARTITION BY id) AS flg 
    FROM database.original_table) x) 

SELECT id 
    , status 
    , prev_date 
FROM (
    SELECT t.id, t.status, t.s, b.prev_date 
    FROM tmp_table t 
    LEFT OUTER JOIN (
    SELECT id, s, MIN(start_date) AS prev_date 
    FROM tmp_table 
    WHERE status='PAID' 
    GROUP BY id, s) b 
    ON b.id=t.id AND b.s=t.s) f 
WHERE status='FREE' 

輸出

id status prev_date 
10 FREE NULL 
10 FREE 2013-05-29 
10 FREE 2014-12-02 
+0

OMG這真棒。你的解決方案完全可行我只是測試了一下。萬分感謝!!。 – pshan99