尝试从一组 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, claimed
。 Claimed
是到intervals
和users
的多对多映射。我希望让多个用户回来,所以我使用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