我有以下数据:
entity_id | 阶段 | old_phase | 时间 | 下一次 |
---|---|---|---|---|
1 | '日志' | 空 | 1654781946989 | 1654781949732 |
1 | '批准' | '日志' | 1654781949732 | 1654781952676 |
1 | '满足' | '批准' | 1654781952676 | 1677506971778 |
1 | '接受' | '满足' | 1677506971778 | 1677518742552 |
1 | '回顾' | '接受' | 1677518742552 | 1678097845979 |
1 | '满足' | '回顾' | 1678097845979 | 1678097847325 |
1 | '接受' | '满足' | 1678097847325 | 1678097977816 |
1 | '回顾' | '接受' | 1678097977816 | 空 |
2 | '日志' | 空 | 1645088036633 | 1645088043676 |
2 | '批准' | '日志' | 1645088043676 | 1645088047318 |
2 | '满足' | '批准' | 1645088047318 | 1677500808099 |
2 | '关闭' | '满足' | 1677500808099 | 空 |
time
和 next_time
表示为以毫秒为单位的 unix 时间戳。
目标是计算每个
entity_id
阶段的每个Fulfill
的持续时间总和。
我的数据库是只读的,所以我不能创建函数。
预期结果应该是这样的:
entity_id | 时长(不包括周六和周日) | 持续时间满 |
---|---|---|
1 | 186天22小时30分21秒 | {“月”:8,“天”:22,“小时”:22,“分钟”:30,“秒”:21} |
2 | 267天3小时32分41秒 | {“年”:1,“天”:15,“小时”:3,“分钟”:32,“秒”:41} |
电流输出:
entity_id | 时长(不包括周六和周日) | 持续时间满 |
---|---|---|
1 | 186天22小时30分19秒 | {“月”:8,“天”:22,“小时”:22,“分钟”:30,“秒”:19} |
1 | -76天0小时0分2秒 | {“秒”:2} |
2 | 267天3小时32分41秒 | {“年”:1,“天”:15,“小时”:3,“分钟”:32,“秒”:41} |
如果
2 Fulfill
上有1 entity_id
相,则输出不正确。
我的 SQL 请求:
WITH temp2 AS (
SELECT
entity_id,
old_phase,
phase,
time,
next_time,
to_timestamp(to_char(to_timestamp("time"/1000.0) at time zone 'Europe/Paris', 'yyyy-mm-dd HH24:MI:SS'), 'yyyy-mm-dd HH24:MI:SS') at time zone 'Europe/Paris' AS "TIME 2",
to_timestamp(to_char(to_timestamp("next_time"/1000.0) at time zone 'Europe/Paris', 'yyyy-mm-dd HH24:MI:SS'), 'yyyy-mm-dd HH24:MI:SS') at time zone 'Europe/Paris'AS "NEXT TIME 2",
((next_time - time)/1000.0) AS DIFF
FROM
tbl_history
WHERE phase = 'Fulfill'
),parms (entity_id, start_date, end_date) AS
(
SELECT
entity_id,
"TIME 2"::timestamp,
"NEXT TIME 2"::timestamp
FROM
temp2
), weekend_days (entity_id, wkend) AS
(
SELECT
entity_id,
SUM(case when extract(isodow from d) in (6, 7) then 1 else 0 end)
FROM
parms
CROSS JOIN
generate_series(start_date, end_date, interval '1 day') dn(d)
GROUP BY entity_id
)
SELECT
entity_id,
CONCAT(
extract(day from diff), ' days ',
extract( hours from diff) , ' hours ',
extract( minutes from diff) , ' minutes ',
extract( seconds from diff)::int , ' seconds '
) AS "Duration (excluding saturday and sunday)",
justify_interval(end_date::timestamp - start_date::timestamp) AS "Duration full"
FROM (
SELECT
start_date,
end_date,
entity_id,
(end_date-start_date) - (wkend * interval '1 day') AS diff
FROM parms
JOIN weekend_days USING(entity_id)
) sq;
演示:https://www.db-fiddle.com/f/ujJe2t9CYLhoRm23RAbSbv/2
如何计算每个 entity_id 的 Fulfill 阶段的完整持续时间(有和没有工作日)?
可以求出每个
sum
的时间间隔(包括justify_interval
)的entity_id
s,求出entity_id
所有间隔之间的周末总数,然后join结果,减去周末数从总和区间:
with cte as (
select t.*, to_timestamp(to_char(to_timestamp(t.time/1000.0) at time zone 'Europe/Paris', 'yyyy-mm-dd HH24:MI:SS'), 'yyyy-mm-dd HH24:MI:SS') at time zone 'Europe/Paris' s,
to_timestamp(to_char(to_timestamp(t.next_time/1000.0) at time zone 'Europe/Paris', 'yyyy-mm-dd HH24:MI:SS'), 'yyyy-mm-dd HH24:MI:SS') at time zone 'Europe/Paris' e
from tbl_history t
),
dt_diff as (
select t.entity_id, t.phase, sum(t.e - t.s) dr, sum(justify_interval(t.e - t.s)) dt
from cte t where t.phase = 'Fulfill' group by t.entity_id, t.phase
),
weekends as (
select t.entity_id, t.phase, sum(case when extract(dow from v) in (0, 6) then 1 else 0 end) wt
from cte t cross join generate_series(t.s, t.e, interval '1 day') v
where t.phase = 'Fulfill' group by t.entity_id, t.phase
)
select t1.entity_id, t1.dr - make_interval(days => w.wt::int) "Duration (excluding saturday and sunday)",
(select jsonb_object_agg(d.key, d.value) from jsonb_each(
jsonb_build_object('years', extract(years from t1.dt),
'months', extract(months from t1.dt),
'days', extract(days from t1.dt),
'hours', extract(hours from t1.dt),
'minutes', extract(minutes from t1.dt),
'seconds', extract(seconds from t1.dt))) d where d.value::int > 0) "Duration full"
from dt_diff t1 join weekends w on w.entity_id = t1.entity_id