Jumlah Interval Tanggal dalam kolom yang sama

10

Bagaimana cara Anda menjumlahkan perbedaan rentang tanggal di kolom yang sama di antara baris yang disatukan? Saya memiliki kolom Datetime dan ingin menghitung perbedaan antara Baris. Saya ingin perbedaan dalam Detik. Pertanyaan ini bukan tentang bagaimana mendapatkan perbedaan antara 2 cap waktu, tetapi lebih fokus pada bagaimana cara menghitung paling efisien antara baris di tabel yang sama. Dalam kasus saya, setiap baris memiliki eventype datetime yang menghubungkan 2 baris secara logis.

Detail Terkait dengan cara mengelompokkan jenis acara mulai dan berakhir. (Pertanyaan Andriy M) Mulai dan Berakhir "harus" berturut-turut. Jika suatu Mulai tidak memiliki akhir berikutnya, ia harus ditinggalkan dari jumlah. Pindah ke Start berikutnya untuk melihat apakah ia memiliki tujuan. Hanya Pasangan Awal - Akhir berurutan yang harus ditambahkan ke jumlah total detik.

Bekerja di postgresql 9.x ...

Contoh data dalam tabel;

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

Catatan, Semua Tanggal Mulai dan Akhir akan berurutan.

Ini usaha pertamaku. Tampaknya bekerja.

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 

Upaya pertama saya didasarkan pada contoh yang bagus dari stackoverflow Postgres 9.1 - Mendapatkan nilai berikutnya

Catatan; Anda dapat mengomentari GROUP BY dan SUM dan tidak mengomentari awal. * Untuk mendapatkan catatan untuk setiap durasi individu masuk ke jumlah.

C Smith
sumber

Jawaban:

10

Anda dapat menggunakan LEADfungsi analitik untuk mendapatkan baris berikutnya eventtypedan di eventdatesamping data baris saat ini:

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'

Menggunakan kueri di atas sebagai tabel turunan, Anda dapat memfilter output lebih lanjut eventtype = 'START' AND nexttype = 'END'dan mendapatkan total perbedaan:

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'
;

Sebagai sedikit variasi, Anda dapat mengimplementasikan subquery sebagai 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'
;

Penulisan ulang ini dapat memiliki implikasi untuk kinerja, karena tidak seperti tabel turunan, CTE terwujud dalam PostgreSQL. Pengujian harus mengungkapkan jika ada perbedaan dan, jika demikian, opsi mana yang lebih baik untuk Anda.

Andriy M
sumber
Andriy, terima kasih! Saya akan mencoba versi CTE dan melihat bagaimana itu membantu.
C Smith