【问题标题】:Finding Gaps in Timestamps with Multiple Users and Overlapping Timeranges in PostgreSQL在 PostgreSQL 中查找具有多个用户和重叠时间范围的时间戳中的差距
【发布时间】:2020-02-10 19:36:12
【问题描述】:

这是本网站上一篇文章的延续:Finding Gaps in Timestamps for Multiple Users in PostgreSQL

我正在使用一个数据集,其中包含过去 5 年中多个办公室的入住和退房时间。我被要求从事的项目之一是计算每个房间在不同时间范围(每天、每周、每月等)内忙碌和空置的时间,假设设定的营业时间(早上 7 点 30 分到下午 5 点)。 与我上一篇文章不同,存在时间范围重叠的情况。一天的数据集样本如下所示:

room_id     check_in                check_out
"Room D"    "2014-07-18 12:23:00"   "2014-07-18 12:54:00"
"Room D"    "2014-07-19 09:16:00"   "2014-07-19 10:30:00"
"Room D"    "2014-07-19 09:10:00"   "2014-07-19 10:30:00"
"Room D"    "2014-07-18 08:45:00"   "2014-07-18 22:40:00"
"Room 5"    "2014-07-19 10:20:00"   "2014-07-19 12:20:00"
"Room 5"    "2014-07-18 07:59:00"   "2014-07-18 09:00:00"
"Room 5"    "2014-07-18 09:04:00"   "2014-07-18 14:00:00"
"Room 5"    "2014-07-18 07:59:00"   "2014-07-18 10:00:00"

在我之前的帖子中,我非常有帮助地获得了这段代码的 sn-p,它完美适用于所有没有重叠的实例,正如作者所指出的:

select date_trunc('day', start_dt), room_id,
       sum( least(extract(epoch from end_dt), v.epoch2) - 
            greatest(extract(epoch from start_dt), epoch1)
          ) as busy_seconds,
       (epoch2 - epoch1 -
        sum( least(extract(epoch from end_dt), v.epoch2) - 
             greatest(extract(epoch from start_dt), epoch1)
           )
       ) as free_seconds
from rooms r cross join
     (values (extract(epoch from date_trunc('day', start_dt) + interval '7 hours 30 minutes'),
              extract(epoch from date_trunc('day', start_dt) + interval '17 hour')
             )
     ) v(epoch1, epoch2)                  
group by date_trunc('day', start_dt), room_id

但是,在挖掘我们的数据后,重叠时间范围的实例比我预期的要多。这是我想从上面的示例数据中检索的目标输出:

target_day      room_id         busy_time         Free Time
2014-07-18      Room D          8.25              1.25
2014-07-19      Room 4          1.33              8.17
2014-07-18      Room 5          8                 1.5
2014-07-19      Room 5          2                 7.5

我现在正在学习 PostgreSQL,所以这个问题有点超出我的想象。任何帮助或指导将不胜感激!

【问题讨论】:

    标签: sql postgresql stored-procedures overlap gaps-and-islands


    【解决方案1】:

    要处理间隙,我建议先将它们组合起来——比如使用 CTE。下面的逻辑是:

    • 查看给定行之前的最长结束日期(对于同一房间和同一时间。
    • 在前一个最大结束日期和开始日期之间存在差距时进行累积求和。
    • 使用它按 room_id 聚合以计算新的开始和结束时间。

    这应该可行,但您可以在将逻辑应用于其他查询之前验证 CTE(唯一的更改是引用 CTE 而不是基表)。

    作为查询:

    with r as (
          select room_id, min(start_dt) as start_dt, max(end_dt) as end_ddt
          from (select r.*,
                       count(*) over (filter where prev_end_dt < start_dt) over (partition by room_id date_trunc('day', start_dt) order by start_dt) as grp
                from (select r.*,
                             max(end_dt) over (partition by room_id, date_trunc('day', start_dt) rows between unbounded preceding and 1 preceding) as prev_end_dt
                      from rooms r
                     ) r
               ) r
          group by room_id, grp
         )
    select date_trunc('day', start_dt), room_id,
           sum( least(extract(epoch from end_dt), v.epoch2) - 
                greatest(extract(epoch from start_dt), epoch1)
              ) as busy_seconds,
           (epoch2 - epoch1 -
            sum( least(extract(epoch from end_dt), v.epoch2) - 
                 greatest(extract(epoch from start_dt), epoch1)
               )
           ) as free_seconds
    from r cross join
         (values (extract(epoch from date_trunc('day', start_dt) + interval '7 hours 30 minutes'),
                  extract(epoch from date_trunc('day', start_dt) + interval '17 hour')
                 )
         ) v(epoch1, epoch2)                  
    group by date_trunc('day', start_dt), room_id
    

    【讨论】:

    • 再次感谢您的帮助!你为我节省了很多时间来完成这一切!
    猜你喜欢
    • 1970-01-01
    • 2020-07-13
    • 1970-01-01
    • 2019-04-17
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-11-14
    • 2019-03-19
    相关资源
    最近更新 更多