2017-04-07 82 views
1

只有在PostgreSQL中打開和關閉事件之間獲得行的最佳方式是什麼?使用分區格式化表格

+------------+----+------------+---------------------+ 
| event_id | ID | occurrence |  datetime  | 
+------------+----+------------+---------------------+ 
| 1003603017 | A | owner_from | 12/16/2016 4:44:16 | 
| 1003603017 | A | owner_to | 12/16/2016 4:44:38 | 
| 1003603017 | A | owner_from | 12/16/2016 4:44:38 | 
| 1003603017 | A | opened  | 12/16/2016 4:44:39 | 
| 1003603017 | B | owner_from | 12/16/2016 7:36:23 | 
| 1003603017 | A | owner_to | 12/16/2016 7:36:23 | 
| 1003603017 | B | owner_to | 12/16/2016 9:00:01 | 
| 1003603017 | C | owner_from | 12/16/2016 9:00:01 | 
| 1003603017 | A | closed  | 12/16/2016 12:00:36 | 
| 1003603017 | D | owner_from | 12/17/2016 4:25:00 | 
| 1003603017 | C | owner_to | 12/17/2016 4:25:00 | 
| 1003603017 | D | owner_from | 12/17/2016 4:52:02 | 
| 1003603017 | D | owner_to | 12/17/2016 4:52:02 | 
| 1003603017 | D | opened  | 12/17/2016 4:52:02 | 
| 1003603017 | D | owner_to | 12/17/2016 8:57:00 | 
| 1003603017 | E | owner_from | 12/17/2016 8:57:00 | 
| 1003603017 | D | closed  | 12/17/2016 12:03:10 | 
+------------+----+------------+---------------------+ 
+5

你怎麼想作爲輸出? –

+1

你試過了什麼?向我們展示您當前的查詢嘗試。 – jarlh

回答

0

查詢使用:

select * from t 
inner join (select event_id, 
        valid_from, 
        valid_to 
      from (select event_id, 
         id, 
         occurrence, 
         lead(occurrence) over (partition by event_id order by datetime) as next_occurrence, 
         datetime as valid_from, 
         lead(datetime) over (partition by event_id order by datetime) as valid_to 
         from t 
         where occurrence in ('opened','closed')) A 
      where occurrence = 'opened') t1 on t.event_id = t1.event_id and t1.valid_from <= t.datetetime and t.datetime <= t1.valid_to 
0

這對於滯後期的ignore nulls選項將會非常容易。下面是一個使用了openedclosed累計最大datetime另一種方法:

select t.* 
from (select t.*, 
      max(case when occurrence = 'opened' then datetime end) over (order by datetime) as mr_opened, 
      max(case when occurrence = 'closed' then datetime end) over (order by datetime) as mr_closed, 
     from t 
    ) t 
where mr_opened > mr_closed; 

注:

  • 這還不包括最終closed。這個要求並不清楚問題。
  • 您可能想要按event_id進行分區。這個要求並不清楚問題。
  • 在更新的Postgres版本中,您可以使用filter語法而不是case
0

您可以使用下面的查詢:

SELECT event_id, ID, occurrence, datetime  
FROM (
    SELECT event_id, ID, occurrence, datetime,  
      COUNT(CASE WHEN occurrence = 'opened' THEN 1 END) 
      OVER (PARTITION BY datetime) AS grp, 
      COUNT(CASE WHEN occurrence = 'opened' THEN 1 END) 
      OVER (ORDER BY datetime) - 
      COUNT(CASE WHEN occurrence = 'closed' THEN 1 END) 
      OVER (ORDER BY datetime) AS slice 
    FROM mytable) AS t 
WHERE t.slice = 1 AND grp <> 1 ; 

使用的第一個窗口條件COUNT有助於識別不opened記錄與opened那些一致。使用這個字段的值,我們可以過濾這些記錄。

第二計算的字段使用中的opened人口運行總計之間的差,closed特技以確定分區開始與openclosed記錄之前終止。

Demo here

0

我做了本身內連接與封閉和接合引線僅選擇地打開和關閉,其中出現在原始表的日期時間是這些值之間。

+0

如果您可以與我們分享您的查詢,我會很有幫助。另外,它如何比較性能與其他兩個答案的查詢? –

0

可以簡單JOIN S(但它需要多)來完成:

select e.* 
from events o 
join events c on c.datetime > o.datetime 
join events e on e.datetime > o.datetime and e.datetime < c.datetime 
where o.occurrence = 'opened' 
and c.occurrence = 'closed' 
and not exists(select 1 
        from events x 
        where x.datetime > o.datetime 
        and x.datetime < c.datetime 
        and x.occurrence in ('opened', 'closed')); 

這可能爲你添加更多的行表將不能很好地擴展,但它有一個可能性使用索引。

另一種選擇是使用窗口功能:

select (e).* 
from (select e, count(1) filter (where occurrence = 'opened') over (order by datetime rows between unbounded preceding and 1 preceding) 
       - count(1) filter (where occurrence = 'closed') over (order by datetime rows between unbounded preceding and current row) open_close 
     from events e) e 
where open_close = 1; 

這一個總是需要全表掃描(也只能)。另一個區別是,如果您沒有關閉occurrence = 'closed'行,則窗口變體將返回最後一行occurrence = 'opened'後的最後一行。

http://rextester.com/FZLV77431