计算多个行的持续时间并分组

时间:2019-07-16 20:25:49

标签: sql postgresql

如果我在PostgreSQL 10.5中有一个带有以下条目的表session_logs

| id  | session_id | recorded_at              | powered | camera_blocked |
| --- | ---------- | ------------------------ | ------- | -------------- |
| 1   | 2          | 2019-06-26T13:40:00.000Z | true    | false          |
| 2   | 2          | 2019-06-26T13:45:00.000Z | false   | false          |
| 3   | 2          | 2019-06-26T13:50:00.000Z | false   | true           |
| 4   | 2          | 2019-06-26T13:55:00.000Z | false   | false          |
| 5   | 6          | 2019-06-26T13:45:00.000Z | true    | false          |
| 6   | 6          | 2019-06-26T13:50:00.000Z | false   | false          |
| 7   | 6          | 2019-06-26T13:55:00.000Z | false   | true           |
| 8   | 6          | 2019-06-26T14:00:00.000Z | false   | false          |

---

我想编写一个查询,该查询将给我以下结果

session_id started_at           ended_at            power_dur battery_dur camera_blocked_dur
--------------------------------------------------------------------------------------
2          2019-06-26 13:40:00 2019-06-26 13:55:00   5        10          5
6          2019-06-26 13:45:00 2019-06-26 14:00:00   5        10          5

如何编写一个查询,该查询在按session_id分组时可以正确地对这些值求和?我有以下内容,但无法正确分组:

with session_log_lead as (
    select sl.*, lead(recorded_at) over (order by recorded_at) as next_recorded_at
    from session_logs as sl
)
select session_id, min(recorded_at) as session_start, max(recorded_at) as session_end,
       sum(next_recorded_at - recorded_at) filter (where powered) as powered_duration,
       sum(next_recorded_at - recorded_at) filter (where powered is false) as battery_duration,
       sum(next_recorded_at - recorded_at) filter (where camera_blocked) as camera_blocked_duration
from session_log_lead
group by session_id

DB Fiddle:https://www.db-fiddle.com/f/7oC2w76QKuS5R4BapiqExW/1

1 个答案:

答案 0 :(得分:1)

只需在窗口函数中添加一个PARTITION BY即可通过每个 session_id 进行计算:

with session_log_lead as (
    select sl.*, lead(recorded_at) over (partition by session_id order by recorded_at) as next_recorded_at
    from session_logs as sl
)
select session_id, 
       min(recorded_at) as session_start, 
       max(recorded_at) as session_end,
       sum(next_recorded_at - recorded_at) filter (where powered) as powered_duration,
       sum(next_recorded_at - recorded_at) filter (where powered is false) as battery_duration,
       sum(next_recorded_at - recorded_at) filter (where camera_blocked) as camera_blocked_duration
from session_log_lead
group by session_id
order by session_id;

Rextester demo

另外,对于分钟的整数值,将EXTRACT(MINUTES FROM ...)添加到聚合中:

EXTRACT(MINUTES FROM sum(next_recorded_at - recorded_at) filter (where powered)) as powered_duration,
EXTRACT(MINUTES FROM sum(next_recorded_at - recorded_at) filter (where powered is false)) as battery_duration,
EXTRACT(MINUTES FROM sum(next_recorded_at - recorded_at) filter (where camera_blocked)) as camera_blocked_duration