2017-04-07 21 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オプションを使用すると非常に簡単です。

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が含まれていないここでopenedclosedの累積最大datetimeを使用する別の方法があります。この要件についての質問は明確ではない。
  • event_idでパーティションすることができます。この要件についての質問は明確ではない。
  • 最近のバージョンのPostgresでは、caseの代わりにfilterの構文を使用できます。
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 ; 

使用された最初のウィンドウの条件付きCOUNTopenedのものと一致していないopenedレコードを識別するのに役立ちます。このフィールドの値を使用して、それらのレコードをフィルタリングすることができます。

第二の計算フィールドは、closedレコード前openと終端で始まるパーティションを決定するために、openedの集団においてclosedトリックを実行している合計の間の差を使用します。

Demo here

0

Iは、内側した開閉に鉛でオカレンスを閉じ、元のテーブル内の日時は、これらの値の間にある接合のみを選択すること自体に参加します。

+0

あなたの質問を私どもと共有することができれば助かります。また、他の2つの回答のクエリとパフォーマンス上の比較はどのように比較されますか? –

0

この(ただし、それは複数必要です)簡単なJOIN秒で行うことができます。

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; 

この1つは、常に全表スキャン(一つだけ)が必要になります。もう1つの違いは、終了するoccurrence = 'closed'行がない場合、ウィンドウバリアントは最後の行の最後の行を返します。occurrence = 'opened'

http://rextester.com/FZLV77431

関連する問題