从具有开始和结束日期的记录列表中获取每个工作日的平均持续时间
Get average duration per week-day from a list of records with start and end date
我有一个包含三列的输入 table :
id
=> 字符串
start_date
=> timestamptz
end_date
=> timestamptz
我想获得每 周-天 条记录的平均持续时间(end_date - start_date)。
我的问题是:如果我有一个记录,其中 start_date 和 end_date 之间的间隔是 4 天,我想每天获取结果,而不仅仅是在 start_date
或 end_date
,例如,如果我在 3 周之间没有记录,则将工作日的任何值作为平均值的 'zero' 值。
示例:
id
start_date
end_date
1 (Friday to Sunday)
2021-03-12T01:00:00.000Z
2021-03-14T01:00:00.000Z
2 (Friday)
2021-03-12T01:00:00.000Z
2021-03-12T05:00:00.000Z
3 (Wed.)
2021-03-03T16:00:00.000Z
2021-03-03T17:00:00.000Z
预期结果(这里以欧洲工作日为例,周日是7):
weekday
avg_duration_seconds
1
0
2
0
3
1800
4
0
5
48600
6
86400
7
3600
感谢您的帮助!
注意:以下内容也适用于您标记的 Postgres。我不知道这是否也适用于 CockroachDB。
您可以使用 generate_series()
将 start/end 时间戳“扩展”到几天。要计算每一天的有效持续时间,需要在开始和结束时将全天与部分天区别对待。一旦计算出这些时间戳,就很容易获得每天的持续时间。在所有工作日进行左连接并按它们分组:
select x.weekday,
avg(extract(epoch from real_end - real_start)) as duration
from generate_series(1,7) as x(weekday)
left join (
select t.id,
extract(isodow from g.dt) as weekday,
case
when start_date < g.dt then date_trunc('day', g.dt)
else start_date
end as real_start,
case
when end_date::date > g.dt then date_trunc('day', g.dt::date + 1)
else end_date
end as real_end
from the_table t
cross join generate_series(start_date, end_date, interval '1 day') as g(dt)
) t on x.weekday = t.weekday
group by x.weekday
order by x.weekday;
我对“real_start”和“real_end”的表达并非 100% 涵盖所有极端情况,但它应该足以让您入门。
结果与您的预期略有不同,因为 2021-03-02 和 2021-03-11 的工作日有误。
我有一个包含三列的输入 table :
id
=> 字符串start_date
=> timestamptzend_date
=> timestamptz
我想获得每 周-天 条记录的平均持续时间(end_date - start_date)。
我的问题是:如果我有一个记录,其中 start_date 和 end_date 之间的间隔是 4 天,我想每天获取结果,而不仅仅是在 start_date
或 end_date
,例如,如果我在 3 周之间没有记录,则将工作日的任何值作为平均值的 'zero' 值。
示例:
id | start_date | end_date |
---|---|---|
1 (Friday to Sunday) | 2021-03-12T01:00:00.000Z | 2021-03-14T01:00:00.000Z |
2 (Friday) | 2021-03-12T01:00:00.000Z | 2021-03-12T05:00:00.000Z |
3 (Wed.) | 2021-03-03T16:00:00.000Z | 2021-03-03T17:00:00.000Z |
预期结果(这里以欧洲工作日为例,周日是7):
weekday | avg_duration_seconds |
---|---|
1 | 0 |
2 | 0 |
3 | 1800 |
4 | 0 |
5 | 48600 |
6 | 86400 |
7 | 3600 |
感谢您的帮助!
注意:以下内容也适用于您标记的 Postgres。我不知道这是否也适用于 CockroachDB。
您可以使用 generate_series()
将 start/end 时间戳“扩展”到几天。要计算每一天的有效持续时间,需要在开始和结束时将全天与部分天区别对待。一旦计算出这些时间戳,就很容易获得每天的持续时间。在所有工作日进行左连接并按它们分组:
select x.weekday,
avg(extract(epoch from real_end - real_start)) as duration
from generate_series(1,7) as x(weekday)
left join (
select t.id,
extract(isodow from g.dt) as weekday,
case
when start_date < g.dt then date_trunc('day', g.dt)
else start_date
end as real_start,
case
when end_date::date > g.dt then date_trunc('day', g.dt::date + 1)
else end_date
end as real_end
from the_table t
cross join generate_series(start_date, end_date, interval '1 day') as g(dt)
) t on x.weekday = t.weekday
group by x.weekday
order by x.weekday;
我对“real_start”和“real_end”的表达并非 100% 涵盖所有极端情况,但它应该足以让您入门。
结果与您的预期略有不同,因为 2021-03-02 和 2021-03-11 的工作日有误。