查询以根据时间间隔计算总和

时间:2020-09-08 13:56:22

标签: sql postgresql

任务包含一个开始时间,日期时间和工作量,以%为单位。
在给定的时间,员工最多可以完成100%的多个任务。 这是一个示例,其中三个任务重叠(可能有四个,五个……):

enter image description here

考虑到每个时间间隔,计算出的百分比分别为:76、101、50和25。

我编写了一种算法,该算法接受输入和输出值中的任务列表,但想了解直接从数据库中检索和是否更有效。问题是,我找不到正确的查询。

有想法的开发者吗?谢谢:)

3 个答案:

答案 0 :(得分:0)

似乎可以通过以下方式执行此操作:首先使用递归CTE生成时间序列(假设数据库支持该时间序列),然后使用between语句在表上保留联接。如果是Postgres,我想您也可以使用一个函数来生成系列。这是一个快速的Postgres示例。这可能需要一些修复,尤其是在连接上。

WITH RECURSIVE TimeSeries AS (
    SELECT NOW() - INTERVAL '10 days' AS RangeStart
    UNION ALL
    SELECT RangeStart + INTERVAL '1 day'
    FROM TimeSeries
    WHERE RangeStart < NOW()
)
SELECT RangeStart, SUM(Workload) AS TotalWorkload
FROM TimeSeries
    LEFT JOIN Workload ON
        Workload.StartTimestamp BETWEEN TimeSeries.RangeStart AND TimeSeries.RangeStart + INTERVAL '1 day'
            OR Workload.EndTimestamp BETWEEN TimeSeries.RangeStart AND TimeSeries.RangeStart + INTERVAL '1 day'

答案 1 :(得分:0)

您必须提取所有不同的期间,然后进行总结

;with
p0 as (
    select id, task, perc, t_start ts, 1 typ
    from time_periods
    UNION ALL
    select id, task, perc, t_end ts, 0 typ
    from time_periods
),
p1 as (
    select *, Lead(ts, 1) over (order by ts) te
    from p0 
),
p2 as (
    select *
    from p1
    where te is not null and ts<>te
)
select p.ts, p.te, sum(t.perc) perc_tot
from p2 p
join time_periods t on not (t.t_end<=p.ts) and not (t.t_start>=p.te)
group by p.ts, p.te
order by 1

答案 2 :(得分:0)

我不确定,我理解正确吗,但可能您需要

WITH taskdata AS (
  SELECT *
    FROM (VALUES(1,'t1','2020-09-09 08:00:00'::timestamp, '2020-09-09 16:00'::timestamp, 25),
                (1,'t2','2020-09-09 08:00:00', '2020-09-09 14:00', 51),
                (1,'t3','2020-09-09 10:00:00', '2020-09-09 18:00', 25)
          ) AS a (uid, taskid, taskstart, taskend, percent)
), checkpoints AS (
  SELECT uid, taskstart AS checkpoint
    FROM taskdata
   UNION
  SELECT uid, taskend
    FROM taskdata
)
SELECT *
  FROM checkpoints AS c
  JOIN LATERAL (
         SELECT sum(percent) AS workload
           FROM taskdata AS t
          WHERE t.uid = c.uid AND
                checkpoint >= taskstart AND
                checkpoint < taskend
       ) AS p ON true
 ORDER BY 1, 2;
 uid |     checkpoint      | workload 
-----+---------------------+----------
   1 | 2020-09-09 08:00:00 |       76
   1 | 2020-09-09 10:00:00 |      101
   1 | 2020-09-09 14:00:00 |       50
   1 | 2020-09-09 16:00:00 |       25
   1 | 2020-09-09 18:00:00 |         
(5 rows)