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

Postgresql 试图从一组30分钟的时间间隔中获取以小时为单位的开始和结束时间,但某些结果无法正确返回,postgresql,gaps-and-islands,Postgresql,Gaps And Islands,我正试图从Postgresql数据库中获取工作时间报告。在输出到报表之前,我将使用Python和Pandas格式化运行其他计算,并使用pd.read_sqq_查询方法使用原始SQL将数据拉入Python 该信息覆盖多个表,用户、时间间隔、声明。声明是到间隔和到用户的多对多映射。我希望返回多个用户,所以我使用partitionbyusername子句对他们进行分组。请让我知道布局是否可能导致问题,因为我下面的示例已经简化了一些 我最近发现了各种关于缺口和孤岛问题的资源,并找到了一个似乎适合我的用例

我正试图从Postgresql数据库中获取工作时间报告。在输出到报表之前,我将使用Python和Pandas格式化运行其他计算,并使用pd.read_sqq_查询方法使用原始SQL将数据拉入Python

该信息覆盖多个表,用户、时间间隔、声明。声明是到间隔和到用户的多对多映射。我希望返回多个用户,所以我使用partitionbyusername子句对他们进行分组。请让我知道布局是否可能导致问题,因为我下面的示例已经简化了一些

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

问题是有些结果并没有达到我的预期。我已经创建了一个SQL FIDLE,其中包含最小可行的 这是岛屿发现的一段。我会选择MAXendtime和MINstarttime,但在某些情况下,我会错过最后的间歇时间

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

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

选择用户名, 岛国, 分钟开始时间为IslandStartDate, 作为IslandEndDate的MAXendtime 从…起 选择*, 案例 当Groups.PreviousEndDate>=starttime时,则为0 其他1 以岛开始结束, 萨姆凯斯 当Groups.PreviousEndDate>=starttime时,则为0 其他1 按组结束分区。用户名 按组排序。RN作为IslandId 从…起 按tr.username选择分区上的行号 由tr.starttime订购, tr.endtime作为rn, tr.username, 斯塔蒂姆, tr.endtime, LAGtr.endtime,1在tr.username分区上 由tr.starttime订购, tr.endtime作为上一个enddate 从时间范围tr 其中tr.starttime介于“2020-03-01”和“2020-03-20”之间 按tr.username组订购 按用户名分组, 岛国 按用户名排序, 岛屿起始日期
我使用窗口函数和公共表表达式重新构造了间隙和孤岛方法,以使其更易于遵循

您可以一次一个地取消注释底部的已注释查询,以逐步了解策略的工作方式


嗨@Mike Organek,谢谢你抽出时间来看看我的问题。我按照您的建议做了,并开始取消对行的注释,但islanid 3仍然存在相同的问题。它返回的结束时间是3:30,而不是预期的4,这就是我想要弄清楚的。取消对fiddler第27行的注释,并查看grp_num 3以了解我的意思。@ScriptingDad您在第3组中有时间旅行问题。轮班从2014年3月3日凌晨3点30分开始,到2013年3月3日凌晨4点结束。你完全正确……我不知道这是怎么发生的。我们必须看看这是否在其他地方出现,并弄清楚它是如何进入那里的。谢谢,这就是我搜索的内容。@ScriptingDad您可能希望向表中添加一个检查约束,以验证starttime╔═════════════╦═════════════════════╦═════════════════════╗ ║ 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 ║ ╚═════════════╩═════════════════════╩═════════════════════╝
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;