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 中插入,我只是简单地求和,但它给了我以下结果:
总计:
- 状态 = 0 - 04:35
- 状态 = 1 - 20:35
- 两者相加 = 25:10:00
我需要的查询应该不考虑属于其他日期的时间部分,该时间不是 24/04/2021 并且必须给我:
2022 年 4 月 24 日总天数:
- 状态 = 0 - 03:25
- 状态 = 1 - 20:35
- 两者相加 = 24:00:00
每天我都需要知道机器在每个状态下停留的时间百分比并构建一个饼图。
有没有办法进行符合此需求的查询?
提前感谢大家的帮助。
@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 日期函数,因此可能有一种更简洁的方法来计算时间。
我有一个记录某台机器的三种状态的应用程序。我需要报告机器每天从 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 中插入,我只是简单地求和,但它给了我以下结果:
总计:
- 状态 = 0 - 04:35
- 状态 = 1 - 20:35
- 两者相加 = 25:10:00
我需要的查询应该不考虑属于其他日期的时间部分,该时间不是 24/04/2021 并且必须给我:
2022 年 4 月 24 日总天数:
- 状态 = 0 - 03:25
- 状态 = 1 - 20:35
- 两者相加 = 24:00:00
每天我都需要知道机器在每个状态下停留的时间百分比并构建一个饼图。
有没有办法进行符合此需求的查询?
提前感谢大家的帮助。
@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 日期函数,因此可能有一种更简洁的方法来计算时间。