PostgresQL 查询计算一天内的时间间隔

PostgresSQL query to count time interval inside day period

我有一个记录某台机器的三种状态的应用程序。我需要报告机器每天从 00:00:00 到 23:59:59 处于每个状态的时间。

我需要帮助来构建 postgresql 查询以获取白天发生某些事件的整个时间间隔。

例如,如下所示,数据显示在前一天 23:50:00 到第二天 01:00:00 之间。

device_id varchar(50) Value int4 Date_time timestamptz
device1 0 2022-23-04 23:50:00
device1 0 2022-24-04 00:10:00
device1 0 2022-24-04 00:15:00
device1 0 2022-24-04 00:20:00
device1 1 2022-24-04 00:25:00
device1 1 2022-24-04 00:30:00
device1 1 2022-24-04 11:00:00
device1 0 2022-24-04 21:00:00
device1 1 2022-25-04 01:00:00

我正在计算状态变化之间的持续时间,我也在 table 中插入,我只是简单地求和,但它给了我以下结果:

总计:

我需要的查询应该考虑属于其他日期的时间部分,该时间不是 24/04/2021 并且必须给我:

2022 年 4 月 24 日总天数:

每天我都需要知道机器在每个状态下停留的时间百分比并构建一个饼图。

有没有办法进行符合此需求的查询?

提前感谢大家的帮助。

@shawnt00 回答有效。现在我想弄清楚如何组织数据,以便查询结果如下:

device_id state_0 state_1 state_9
device_id timespan_state_0 timespan_state_1 timespan_state_9

对于给定的示例,应该如下所示,我添加了第二个设备只是为了扩充示例:)

device_id state_0 state_1 state_9
device1 03:25 20:35 00:00
device2 X Y Z

附件

获胜者马丁斯

下面的查询可以。

select
    std.state,
    sum(case 
            when std.rk = 1 then std.time_diff + std.time_diff_start
            when std.trunc_state_start = std.trunc_state_end then std.time_diff
            when std.trunc_state_start <> std.trunc_state_end then std.time_diff_end
            else std.time_diff
        end)
from
    (
    select
        a.state,
        date_trunc('day', a.date_time) as trunc_state_start,
        date_trunc('day', b.date_time) as trunc_state_end,
        b.date_time - a.date_time as time_diff,
        a.date_time - date_trunc('day', a.date_time) as time_diff_start,
        date_trunc('day', b.date_time) - a.date_time as time_diff_end,
        rank() over(order by a.date_time) rk
    from
        (select ds.*, rank() over(order by date_time) rk from devicestat ds) a
    inner join 
        (select ds.*, rank() over(order by date_time) rk from devicestat ds) b 
    on
        a.rk + 1 = b.rk
    where
        date_trunc('day', a.date_time) = '2022-04-24') std
group by
    std.state;

本身的joining让我很容易计算状态开始和结束时间的时间差。剩下的就是如何计算一天开始和结束之间的边界差异。我认为有很多方法可以做到这一点,但这是我想到的。

我认为您只需要使用 lead()/lag() 和一些 case 表达式来检测午夜的跨度。不需要加入:

with data as (
    select *,
        cast(date_trunc('day', Date_time) as date) as dt,
        lag(Date_time) over (partition by device_id order by Date_time) as last_Date_time,
        lead(Date_time) over (partition by device_id order by Date_time) as next_Date_time
    from T
)
select device_id, dt as "date", Value,
    coalesce(sum(
        case when date_trunc('day', next_Date_time) > date_trunc('day', Date_time)
             then date_trunc('day', Date_time + interval '1 day') - Date_time
             else coalesce(next_date_time - Date_time, interval '0 seconds') end
        +
        case when date_trunc('day', last_Date_time) < date_trunc('day', Date_time)
             then Date_time - date_trunc('day', Date_time)
             else interval '0 seconds' end
    ), interval '0 seconds') as timespan2
from data
group by device_id, dt, Value
order by device_id, dt, Value;

https://dbfiddle.uk/?rdbms=postgres_12&fiddle=ab32fee1615b637f9f2f844aa1bf5064

我不太熟悉所有 PostGres 日期函数,因此可能有一种更简洁的方法来计算时间。