在几个均匀分布的时间间隔内分解时间聚合数据
Breaking down of time aggregated data on several evenly distributed intervals
数据库结构如下所示。
它只是代表员工的一行,正在处理的任务数量,开始的事实 activity 以及结束的事实和所用秒数的总摘要。
employee
number_of_tasks
start_act
end_act
total_seconds
AXF-6263
5
12:30
14:10
6000
我想以相等的间隔将其分解,每次 1 小时,另外总结总秒数,落入特定间隔。从而得到这样的结果。那么有什么 SQL 方法可以解决这个问题吗?
employee
number_of_tasks
start_act
end_act
total_seconds
AXF-6263
5
12:00
13:00
1800
AXF-6263
5
13:00
14:00
3600
AXF-6263
5
14:00
15:00
600
在此先感谢您的帮助!
使用 generate_series
并将其与您的 table 交叉连接。
-- Test case
create temporary table the_table (employee text, number_of_tasks integer, start_act time, end_act time, total_seconds integer);
insert into the_table values ('AXF-6263', 5, '12:30', '14:10', 6000);
-- Query
select employee, number_of_tasks,
h::time start_act, h::time + interval '1 hour' end_act,
extract('epoch' from least(h::time + interval '1 hour', end_act) - greatest(h::time, start_act))::integer total_seconds
from the_table cross join lateral
generate_series(date_trunc('hour', current_date + start_act), date_trunc('hour', current_date + end_act), interval '1 hour') h
order by h;
employee
number_of_tasks
start_act
end_act
total_seconds
AXF-6263
5
12:00:00
13:00:00
1800
AXF-6263
5
13:00:00
14:00:00
3600
AXF-6263
5
14:00:00
15:00:00
600
有趣的任务,我决定加入一个系列,然后找出他的重叠。
我的方法是使用灵活的时间单位,因此您可以更改为 days/weeks/etc
with employees AS (
SELECT
'AXF-6263' AS employee,
5 AS number_of_tasks,
'2022-03-25 12:30'::timestamp AS start_act,
'2022-03-25 14:10'::timestamp AS end_act,
6000 AS total_seconds
),
-- select a set of employees to work on
sample_set AS (
SELECT
employee,
start_act,
end_act
FROM
employees
-- WHERE ...
-- LIMIT ...
),
-- choose a unit for the interval
unit AS (
SELECT
'hour' AS unit,
'1 hour'::interval AS interval
),
-- generate a full series of time intervals
time_spans AS (
SELECT
sample_set.employee,
generate_series(
min(date_trunc(unit.unit, start_act)),
max(date_trunc(unit.unit, end_act)),
unit.interval
) AS start_act
FROM
sample_set
JOIN unit
ON true
GROUP BY
employee,
unit.interval
)
-- final results
SELECT
employee,
number_of_tasks,
time_spans.start_act,
time_spans.start_act + unit.interval AS end_act,
CASE
WHEN employees.start_act > time_spans.start_act THEN time_spans.start_act - employees.start_act + unit.interval
WHEN employees.end_act < time_spans.start_act + unit.interval THEN employees.end_act - time_spans.start_act
ELSE unit.interval
END AS total_seconds
FROM
employees
JOIN time_spans USING (employee)
JOIN unit ON
true
ORDER BY
employee,
time_spans.start_act
数据库结构如下所示。 它只是代表员工的一行,正在处理的任务数量,开始的事实 activity 以及结束的事实和所用秒数的总摘要。
employee | number_of_tasks | start_act | end_act | total_seconds |
---|---|---|---|---|
AXF-6263 | 5 | 12:30 | 14:10 | 6000 |
我想以相等的间隔将其分解,每次 1 小时,另外总结总秒数,落入特定间隔。从而得到这样的结果。那么有什么 SQL 方法可以解决这个问题吗?
employee | number_of_tasks | start_act | end_act | total_seconds |
---|---|---|---|---|
AXF-6263 | 5 | 12:00 | 13:00 | 1800 |
AXF-6263 | 5 | 13:00 | 14:00 | 3600 |
AXF-6263 | 5 | 14:00 | 15:00 | 600 |
在此先感谢您的帮助!
使用 generate_series
并将其与您的 table 交叉连接。
-- Test case
create temporary table the_table (employee text, number_of_tasks integer, start_act time, end_act time, total_seconds integer);
insert into the_table values ('AXF-6263', 5, '12:30', '14:10', 6000);
-- Query
select employee, number_of_tasks,
h::time start_act, h::time + interval '1 hour' end_act,
extract('epoch' from least(h::time + interval '1 hour', end_act) - greatest(h::time, start_act))::integer total_seconds
from the_table cross join lateral
generate_series(date_trunc('hour', current_date + start_act), date_trunc('hour', current_date + end_act), interval '1 hour') h
order by h;
employee | number_of_tasks | start_act | end_act | total_seconds |
---|---|---|---|---|
AXF-6263 | 5 | 12:00:00 | 13:00:00 | 1800 |
AXF-6263 | 5 | 13:00:00 | 14:00:00 | 3600 |
AXF-6263 | 5 | 14:00:00 | 15:00:00 | 600 |
有趣的任务,我决定加入一个系列,然后找出他的重叠。
我的方法是使用灵活的时间单位,因此您可以更改为 days/weeks/etc
with employees AS (
SELECT
'AXF-6263' AS employee,
5 AS number_of_tasks,
'2022-03-25 12:30'::timestamp AS start_act,
'2022-03-25 14:10'::timestamp AS end_act,
6000 AS total_seconds
),
-- select a set of employees to work on
sample_set AS (
SELECT
employee,
start_act,
end_act
FROM
employees
-- WHERE ...
-- LIMIT ...
),
-- choose a unit for the interval
unit AS (
SELECT
'hour' AS unit,
'1 hour'::interval AS interval
),
-- generate a full series of time intervals
time_spans AS (
SELECT
sample_set.employee,
generate_series(
min(date_trunc(unit.unit, start_act)),
max(date_trunc(unit.unit, end_act)),
unit.interval
) AS start_act
FROM
sample_set
JOIN unit
ON true
GROUP BY
employee,
unit.interval
)
-- final results
SELECT
employee,
number_of_tasks,
time_spans.start_act,
time_spans.start_act + unit.interval AS end_act,
CASE
WHEN employees.start_act > time_spans.start_act THEN time_spans.start_act - employees.start_act + unit.interval
WHEN employees.end_act < time_spans.start_act + unit.interval THEN employees.end_act - time_spans.start_act
ELSE unit.interval
END AS total_seconds
FROM
employees
JOIN time_spans USING (employee)
JOIN unit ON
true
ORDER BY
employee,
time_spans.start_act