同じ列内の日付の合計間隔


10

インターリーブする行間の同じ列の日付の範囲の違いをどのように合計するのが最適ですか?日時列があり、行間の差を計算したいと思います。秒の差が欲しい。この質問は、2つのタイムスタンプの違いを取得する方法ではなく、同じテーブルの行間で最も効率的に計算する方法に重点を置いています。私の場合、各行には2つの行を論理的にリンクするdatetimeのeventypeがあります。

開始と終了のイベントタイプをグループ化する方法に関連する詳細。(Andriy Mの質問)開始と終了は「すべき」です。開始に後続の終了がない場合は、合計から除外する必要があります。次の開始に移動して、終了があるかどうかを確認します。合計秒数の合計には、連続する開始-終了ペアのみを追加する必要があります。

postgresql 9.xでの作業...

表のデータの例。

eventtype, eventdate
START, 2015-01-01 14:00
END, 2015-01-01 14:25
START, 2015-01-01 14:30
END, 2015-01-01 14:43
START, 2015-01-01 14:45
END, 2015-01-01 14:49
START, 2015-01-01 14:52
END, 2015-01-01 14:55

すべての開始日と終了日は連続していることに注意してください。

これが私の最初の試みです。動作しているようです。

SELECT 
-- starts.*
SUM(EXTRACT(EPOCH FROM (eventdate_next - eventdate))) AS duration_seconds
FROM
( 
    WITH x AS (
        SELECT *, dense_rank() OVER (ORDER BY eventdate) AS rnk
        FROM   table
        AND eventdate > '2015-01-01 00:00:00.00'
        AND eventdate < '2016-01-01 23:59:59.59' 
        )
    SELECT x.eventdate, x.eventtype, y.eventdate AS eventdate_next,  y.eventtype AS eventtype_next
    FROM   x
    LEFT   JOIN (SELECT DISTINCT eventdate, eventtype, rnk FROM x) y ON y.rnk = (x.rnk + 1)
    ORDER  BY x.eventdate
) starts
WHERE
eventtype = 'START'   
GROUP BY eventtype 

私の最初の試みは、stackoverflow Postgres 9.1-次の値の取得からの優れた例に基づいてい ます

注意; GROUP BYとSUMにコメントを付け、starts。*のコメントを外して、合計に入る個々の期間のレコードを取得できます。

回答:


10

あなたは使用することができLEAD、次の行の取得するために分析関数をeventtypeし、eventdate現在の行のデータと一緒に:

SELECT
  eventtype,
  eventdate,
  LEAD(eventtype) OVER (ORDER BY eventdate) AS nexttype,
  LEAD(eventdate) OVER (ORDER BY eventdate) AS nextdate
FROM
  atable
WHERE
      eventdate >= '2015-01-01 00:00:00.00'
  AND eventdate <  '2016-01-01 23:59:59.59'

上記のクエリを派生テーブルとして使用すると、出力をさらにフィルタリングしeventtype = 'START' AND nexttype = 'END'て差分の合計を取得できます。

SELECT
  SUM(EXTRACT(EPOCH FROM (nextdate - eventdate))) AS duration_seconds
FROM
  (
    SELECT
      eventtype,
      eventdate,
      LEAD(eventtype) OVER (ORDER BY eventdate) AS nexttype,
      LEAD(eventdate) OVER (ORDER BY eventdate) AS nextdate
    FROM
      atable
    WHERE
          eventdate >= '2015-01-01 00:00:00.00'
      AND eventdate <  '2016-01-01 23:59:59.59'
  ) AS s
WHERE
      eventtype = 'START'
  AND nexttype  = 'END'
;

わずかなバリエーションとして、サブクエリをCTEとして実装できます。

WITH cte AS
  (
    SELECT
      eventtype,
      eventdate,
      LEAD(eventtype) OVER (ORDER BY eventdate) AS nexttype,
      LEAD(eventdate) OVER (ORDER BY eventdate) AS nextdate
    FROM
      atable
    WHERE
          eventdate >= '2015-01-01 00:00:00.00'
      AND eventdate <  '2016-01-01 23:59:59.59'
  )
SELECT
  SUM(EXTRACT(EPOCH FROM (nextdate - eventdate))) AS duration_seconds
FROM
  cte
WHERE
      eventtype = 'START'
  AND nexttype  = 'END'
;

派生テーブルとは異なり、CTEはPostgreSQLで実現されるため、この書き換えはパフォーマンスに影響を与える可能性があります。テストでは、違いがあるかどうか、ある場合はどちらのオプションが適しているかを明らかにする必要があります。


アンドリー、ありがとう!CTEバージョンを試して、それがどのように役立つかを確認します。
C Smith
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.