2016-06-14 65 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