如何使用PostgreSQL将开始/结束时间列拆分为离散块?

Ant*_*ony 4 postgresql datetime

我们有一些表,其结构如下:

start, - datetime
end, - datetime
cost - decimal

因此,例如,可能会有一行如下:

01/01/2010 10:08 am,
01/01/2010 1:56 pm,135.00 01/01/2010 11:01 am,01/01/2010 3:22 pm,118.00
01/01/2010 06:19 pm,01/02/2010 1:43 am,167.00

等等...

我想把它变成一种格式(带有函数?),它以如下格式返回数据:

上午10:00,上午10:15,X,Y,Z
上午10:15,上午10:30,X,Y,Z
上午10:30,上午10:45,X,Y,Z
上午10:45,上午11:00,X,Y ,Z
上午11:00,上午11:15,X,Y,Z

....

其中:
X =匹配的行数
Y =该大块时间的成本/费用
Z =此期间的总时间量

IE,对于上述数据,我们可能会:

上午10:00,上午10:15,1,(135/228分钟*7),7

  • 第一行从上午10:08开始,因此从10​​:00-10:15仅使用7分钟.
  • 开始 - >结束时间有228分钟.

....

上午11:00,上午11:15,2,((135 + 118)/((228 + 261)分钟*(15 + 14)),29

  • 第二行在上午11:00之后开始,所以我们需要从第一行开始15分钟,再从第二行开始需要14分钟
  • 在第二个开始 - >结束时间有261分钟

....

我相信我已经在这里完成了数学计算,但是需要弄清楚如何将它变成PG函数,以便它可以在报告中使用.

理想情况下,我希望能够以任意持续时间调用该函数,即15分钟,或30分钟,或60分钟,并根据它分开.

有任何想法吗?

jir*_*ira 5

这是我的尝试.鉴于此表定义:

CREATE TABLE interval_test
(
  "start" timestamp without time zone,
  "end" timestamp without time zone,
  "cost" integer
)
Run Code Online (Sandbox Code Playgroud)

这个查询似乎做你想要的.但不确定它是否是最佳解决方案.还要注意它需要Postgres 8.4才能工作,因为它使用WINDOW函数和WITH查询.

WITH RECURSIVE intervals(period_start) AS (
    SELECT 
    date_trunc('hour', MIN(start)) AS period_start
      FROM interval_test

  UNION ALL
    SELECT intervals.period_start + INTERVAL '15 MINUTES'
      FROM  intervals
      WHERE (intervals.period_start + INTERVAL '15 MINUTES') < (SELECT MAX("end") FROM interval_test)
  )
  SELECT DISTINCT period_start, intervals.period_start + INTERVAL '15 MINUTES' AS period_end, 
  COUNT(*) OVER  (PARTITION BY period_start ) AS record_count,
SUM (LEAST(period_start + INTERVAL '15 MINUTES', "end")::timestamp - GREATEST(period_start, "start")::timestamp)
  OVER  (PARTITION BY period_start ) AS total_time,

  (SUM(cost) OVER  (PARTITION BY period_start ) /  


 (EXTRACT(EPOCH FROM SUM("end" - "start") OVER  (PARTITION BY period_start )) / 60)) * 

 ((EXTRACT (EPOCH FROM SUM (LEAST(period_start + INTERVAL '15 MINUTES', "end")::timestamp - GREATEST(period_start, "start")::timestamp)
  OVER  (PARTITION BY period_start )))/60)

   AS expense

FROM  interval_test
INNER JOIN intervals ON (intervals.period_start, intervals.period_start + INTERVAL '15 MINUTES') OVERLAPS (interval_test.start, interval_test.end)

ORDER BY period_start ASC
Run Code Online (Sandbox Code Playgroud)