尝试从一组 30 分钟的时间间隔中获取以小时为单位的开始和结束时间,但某些结果未正确返回

Posted

技术标签:

【中文标题】尝试从一组 30 分钟的时间间隔中获取以小时为单位的开始和结束时间,但某些结果未正确返回【英文标题】:Trying to get start and end time in hours from a set of 30 minute time intervals and some results aren't returning correctly 【发布时间】:2020-07-15 16:08:57 【问题描述】:

我正在尝试从 Postgresql 数据库中获取工作时间的报告。在输出到报告之前,我将使用 Python 和 Pandas 格式化运行附加计算,并且我使用 pd.read_sqq_query() 方法使用原始 SQL 将数据拉入 python。

信息来自多个表users, intervals, claimedClaimed 是到intervalsusers 的多对多映射。我希望让多个用户回来,所以我使用PARTITION BY username 子句对它们进行分组。请让我知道布局是否可能导致问题,因为我下面的示例已经简化了一些。

我最近发现了各种关于差距和孤岛问题的资源,并找到了一个似乎适合我已经适应工作的用例的资源; 参考:Gaps and islands。它似乎是 MSSQL,但我不相信它在那里提到。

问题是某些结果没有返回我期望的结果。我创建了一个 SQL Fiddle,最小可行sqlfiddle

这是岛屿发现的部分之一。我正在使用 MAX(endtime) 和 MIN(starttime) 但在某些情况下我错过了最后的时间间隔。

例如:下表有一个段,我希望它将开始时间显示为2020-03-08T0:00:00,结束时间显示为2020-03-08T4:00:00,但我实际上将结束时间显示为2020-03-08T3:30:00

╔═════════════╦═════════════════════╦═════════════════════╗
║  Username   ║     Start Time      ║      End Time       ║
╠═════════════╬═════════════════════╬═════════════════════╣
║ Test User 1 ║ 2020-03-08T02:00:00 ║ 2020-03-08T02:30:00 ║
║ Test User 1 ║ 2020-03-08T02:30:00 ║ 2020-03-08T03:00:00 ║
║ Test User 1 ║ 2020-03-08T03:00:00 ║ 2020-03-08T03:30:00 ║
║ Test User 1 ║ 2020-03-08T03:30:00 ║ 2020-03-08T04:00:00 ║
╚═════════════╩═════════════════════╩═════════════════════╝

这是我在 SQLFiddle 中的示例,还有更多数据,但都是针对一个用户的。

SELECT username,
       islandId,
       MIN(starttime) as IslandStartDate,
       MAX(endtime) as IslandEndDate
FROM
        (SELECT *,
                CASE
                    WHEN Groups.PreviousEndDate >= starttime THEN 0
                    ELSE 1
                END as IslandStartInd,
                SUM(CASE
                        WHEN Groups.PreviousEndDate >= starttime then 0
                        else 1
                    end) OVER (PARTITION BY Groups.username
                               ORDER BY Groups.RN) as IslandId
         FROM
                 ( SELECT ROW_NUMBER() over (PARTITION BY tr.username
                                             order by tr.starttime,
                                                      tr.endtime) as rn ,
                                            tr.username ,
                                            tr.starttime ,
                                            tr.endtime ,
                                            LAG(tr.endtime, 1) OVER (PARTITION BY tr.username
                                                                     ORDER BY tr.starttime,
                                                                              tr.endtime) as PreviousEndDate
                  FROM timerange tr
                  WHERE tr.starttime BETWEEN '2020-03-01' AND '2020-03-20'
                  ORDER BY tr.username) Groups ) Islands
Group BY username,
         islandid
ORDER BY username,
         IslandStartDate

【问题讨论】:

【参考方案1】:

我使用窗口函数和公用表表达式重新构建了间隙和孤岛方法,使其更易于理解。

您可以取消注释底部的注释查询(一次一个),以逐步了解该策略的工作原理。

The sqlfiddle.

with gaps as (
  select *,
         case 
           when starttime = lag(endtime) over (partition by username 
                                                     order by starttime) then 0
           else 1
         end as gap_begin_row_marker
    from timerange
), grp_numbers as (
  select username, starttime, endtime,
         sum(gap_begin_row_marker) over (partition by username
                                             order by starttime) as grp_num
    from gaps
), collapsed_intervals as(
  select grp_num, username, min(starttime) as starttime, max(endtime) as endtime
    from grp_numbers
   group by grp_num, username
), summed_time as (
  select username, sum(endtime - starttime) as time_claimed
    from collapsed_intervals
   group by username
)
/* select * from gaps; */
/* select * from grp_numbers; */
/* select * from collapsed_intervals; */
select * from summed_time;

【讨论】:

嗨@Mike Organek,感谢您抽出宝贵时间查看我的问题。我按照你的建议做了,并开始取消注释这些行,但 islanid 3 仍然有同样的问题。它将结束时间返回为 3:30 而不是预期的 4,这就是我想要弄清楚的。取消注释您的提琴手的第 27 行并查看 grp_num 3 以了解我的意思。 @ScriptingDad 您在第 3 组中遇到时间旅行问题。班次从 03/14 的 0330 开始,到 03/13 的 0400 结束。 你是绝对正确的......我不知道它是如何进入那里的。将不得不看看这是否出现在其他地方,并弄清楚它是如何进入那里的。谢谢,这就是我正在寻找的。​​span> @ScriptingDad 你可能想在你的表中添加一个检查约束来验证starttime < endtime 看起来这可能是由于我如何将输入时间转换为 UTC 时间造成的。时间通常以 EST/EDT 时间输入并分区为 UTC。不知道为什么要这样做,但我知道现在该往哪里看。感谢您的帮助!

以上是关于尝试从一组 30 分钟的时间间隔中获取以小时为单位的开始和结束时间,但某些结果未正确返回的主要内容,如果未能解决你的问题,请参考以下文章

以分钟为单位显示时间间隔 - Kendo Scheduler

在 MySQL 中聚合/分组一组行/记录

给定熊猫中只有小时-分钟-秒格式的列,如何以秒为单位返回总时间? [关闭]

时间分割与获取一下阶段时间

以小时和分钟获取当前时间

Oracle中的时间间隔型数据掌握方法