【问题标题】:Finding Gaps in Timestamps for Multiple Users in PostgreSQL在 PostgreSQL 中查找多个用户的时间戳差距
【发布时间】:2020-02-06 22:27:54
【问题描述】:

我正在使用一个数据集,其中包含过去 5 年中多个办公室的入住和退房时间。我被要求从事的项目之一是计算每个房间在不同时间范围(每天、每周、每月等)内忙碌和空置的时间,假设正常工作时间(上午 8 点到下午 5 点)。两天的数据集样本如下所示:

room_id         start_dt                end_dt
Room: Room 3    2019-05-04 09:00:00     2019-05-04 11:30:00
Room: Room 3    2019-05-04 11:30:00     2019-05-04 12:15:00
Room: Room 3    2019-05-04 12:30:00     2019-05-04 13:00:00
Room: Room 3    2019-05-05 09:00:00     2019-05-05 13:00:00
Room: Room 4    2019-05-04 08:00:00     2019-05-04 09:00:00
Room: Room 4    2019-05-04 09:00:00     2019-05-04 11:00:00
Room: Room 4    2019-05-04 14:00:00     2019-05-04 16:00:00
Room: Room 4    2019-05-05 08:30:00     2019-05-05 09:30:00

我借用并修改了@Branko Dimitrijevic 之前的 StackOverflow 帖子(完整帖子:SQL Query to show gaps between multiple date ranges)中编写的一些代码,以尝试处理多个不同的房间。下面是我修改后的代码,在 SELECT 子句中有两个 room_id 实例,用于调试目的:

SELECT t1.room_id, t2.room_id, end_dt, start_dt, start_dt - end_dt as gap_dur
FROM
    (
        SELECT DISTINCT room_id, start_dt, ROW_NUMBER() OVER (ORDER BY start_dt) RN
        FROM my_table T1
        WHERE
            NOT EXISTS (
                SELECT *
                FROM my_table T2
                WHERE (T1.start_dt > T2.start_dt and t1.resource = t2.resource)
                    AND (T1.start_dt < T2.end_dt and t1.resource = t2.resource)
            )
        ) T1
    JOIN (
        SELECT DISTINCT resource, end_dt, ROW_NUMBER() OVER (ORDER BY end_dt) RN
        FROM my_table T1
        WHERE
            NOT EXISTS (
                SELECT *
                FROM my_table T2
                WHERE (T1.end_dt > T2.start_dt and t1.resource = t2.resource)
                    AND (T1.end_dt < T2.end_dt and t1.resource = t2.resource)
            )
    ) T2
    ON T1.RN - 1 = T2.RN
WHERE
    end_dt < start_dt

这是我收到的输出:

room_id         room_id         end_dt                  start_dt                gap_dur
Room: Exam 4    Room: Exam 4    2019-05-04 16:00:00     2019-05-05 08:30:00     16:30:00
Room: Exam 4    Room: Exam 3    2019-05-04 13:00:00     2019-05-04 14:00:00     01:00:00
Room: Exam 3    Room: Exam 3    2019-05-04 12:15:00     2019-05-04 12:30:00     00:15:00

但是,这在不同房间之间变得很混乱,我不知道如何实施工作日限制,例如查找上午 8 点和第一个预定活动之间的时间间隔。下面是一个最佳输出,或者至少是一种数据格式,可用于通过一些简单的 GROUP BY 脚本计算我需要的统计数据:

room_id         end_dt                  start_dt                gap_dur
Room: Exam 3    2019-05-04 08:00:00     2019-05-04 09:00:00     01:00:00
Room: Exam 3    2019-05-04 12:15:00     2019-05-04 12:30:00     00:15:00
Room: Exam 3    2019-05-04 13:00:00     2019-05-04 17:00:00     04:00:00
Room: Exam 3    2019-05-05 08:00:00     2019-05-05 09:00:00     01:00:00
Room: Exam 3    2019-05-05 13:00:00     2019-05-05 17:00:00     04:00:00
Room: Exam 4    2019-05-04 11:00:00     2019-05-04 14:00:00     03:00:00
Room: Exam 4    2019-05-04 16:00:00     2019-05-04 17:00:00     01:00:00
Room: Exam 4    2019-05-05 08:00:00     2019-05-05 08:30:00     00:30:00
Room: Exam 4    2019-05-05 09:30:00     2019-05-05 17:00:00     09:30:00

对此的任何帮助将不胜感激,如果有帮助,我们很乐意提供更多信息!

【问题讨论】:

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


    【解决方案1】:

    我被要求从事的一个项目是计算每个房间在不同时间范围内(每天、每周、每月等)的忙碌和空置时间,假设正常营业时间(早上 8 点到下午 5 点)。

    根据您的样本数据,有两个假设似乎是合理的:

    • “忙碌”时段不重叠。
    • “忙碌”时段都在一天之内。

    如果这些不正确,我建议您提出一个带有适当解释和示例数据的新问题。

    对于给定的一天,计算非常简单:

    select date_trunc('day', start_dt),
           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 '8 hour'),
                  extract(epoch from date_trunc('day', start_dt) + interval '17 hour')
                 )
         ) v(epoch1, epoch2)                  
    group by date_trunc('day', start_dt)
    

    【讨论】:

    • 嗨@Gordon,你的假设是完全正确的!在完整的数据集中,可能有一些重叠,因为这在系统中技术上是可行的,但它们应该非常罕见。因此,感谢您提供的代码 sn-p 它非常有用!
    • @user2789531 。 . .如果您需要有关重叠的帮助,请使用适当的示例数据提出一个新问题。
    猜你喜欢
    • 1970-01-01
    • 2012-12-10
    • 2020-07-13
    • 2022-12-20
    • 2019-01-27
    • 2017-01-23
    • 2021-01-12
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多