ผลรวมช่วงเวลาของวันที่ภายในคอลัมน์เดียวกัน


10

คุณจะหาผลรวมของความแตกต่างของช่วงวันที่ในคอลัมน์เดียวกันระหว่างแถวแทรกได้อย่างไร ฉันมีคอลัมน์ Datetime และต้องการคำนวณความแตกต่างระหว่างแถว ฉันต้องการความแตกต่างในวินาที คำถามนี้ไม่ได้เกี่ยวกับวิธีสร้างความแตกต่างระหว่างการประทับเวลา 2 ครั้ง แต่จะเน้นไปที่วิธีการคำนวณที่มีประสิทธิภาพมากที่สุดระหว่างแถวในตารางเดียวกัน ในกรณีของฉันแต่ละแถวมีประเภทกิจกรรมวันที่ที่เชื่อมโยงกัน 2 แถวด้วยกันอย่างมีเหตุผล

รายละเอียดที่เกี่ยวข้องกับวิธีการจัดกลุ่มประเภทเหตุการณ์ของการเริ่มต้นและสิ้นสุด (คำถามของ 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 และยกเลิกการแสดงความคิดเห็นการเริ่มต้น * เพื่อรับการบันทึกสำหรับแต่ละช่วงเวลาที่จะรวมกัน

คำตอบ:


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.