因此,我的目标是能够计算在小时范围内用于某些活动的时间。
我的数据包含:某些活动的开始和结束, 例如我知道有人从'2019-01-09 17:04:34'中断到'2019-01-09 19:55:03'。
我的目标是计算此人在“ 17-18”间隔中休息55分钟,在“ 18-19”间隔60分钟,在“ 19-20”间隔55分钟。
我的想法是始终拆分源,因此对于包含start和活动的行,我将收到与时间范围(在小时范围内)划分的行一样多的行(对于此示例数据,我将收到3行: 2019-01-09 17:04:34'至'2019-01-09 17:59:59','2019-01-09 18:00:00'至'2019-01-09 18:59:59'和“ 2019-01-09 19:00:00”到“ 2019-01-09 19:55:03”)
如果我能获得类似的东西,我就可以算出我需要的所有东西。我预计要获得此结果,我应该使用CTE(因为我们不知道需要分割时间间隔的范围是多少),但是我对此没有经验。
希望我能清楚地解释我的问题。我在oracle sql开发人员上工作。
非常感谢您的帮助,至少提供了一些提示。
答案 0 :(得分:0)
由于您提到了递归,因此使用了递归子查询分解:
-- CTE for sample data
with your_table (id, start_time, end_time) as (
select 1, timestamp '2019-01-09 17:04:34', timestamp '2019-01-09 19:55:03' from dual
union all
select 2, timestamp '2019-01-09 23:47:01', timestamp '2019-01-10 02:05:03' from dual
union all
select 3, timestamp '2019-01-09 18:01:01', timestamp '2019-01-09 18:02:07' from dual
union all
select 4, timestamp '2019-01-09 13:00:00', timestamp '2019-01-09 14:00:01' from dual
),
-- recursive CTE
rcte (id, hour_period, minutes, period_start_time, end_time, hour_num) as (
select id,
-- first period is the original start hour
extract(hour from start_time),
-- minutes in first period, which can end at the end of that hour, or at original
-- end time if earlier
case when extract(minute from end_time) = 0
and end_time >= cast(trunc(start_time, 'HH') as timestamp) + interval '1' hour
then 60
else extract(minute from
least(cast(trunc(start_time, 'HH') as timestamp) + interval '1' hour, end_time)
- start_time
)
end,
-- calculate next period start
cast(trunc(start_time, 'HH') as timestamp) + interval '1' hour,
-- original end time
end_time,
-- first hour period (for later ordering)
1
from your_table
union all
select id,
-- this period's hour value
extract(hour from period_start_time),
-- minutes in this period - either 60 if we haven't reach the end time yet;
-- or if we have then the number of minutes from the end time
case when end_time < period_start_time + interval '1' hour
then extract(minute from end_time)
else 60
end,
-- calculate next period start
period_start_time + interval '1' hour,
-- original end time
end_time,
-- increment hour period (for later ordering)
hour_num + 1
from rcte
where period_start_time < end_time
)
select id, hour_period, minutes
from rcte
order by id, hour_num;
ID HOUR_PERIOD MINUTES
---------- ----------- ----------
1 17 55
1 18 60
1 19 55
2 23 12
2 0 60
2 1 60
2 2 5
3 18 1
4 13 60
4 14 0
它找到在锚成员中该时间段的第一个小时所花费的时间,然后递归地查看随后的几小时,直到达到结束时间为止,每次都增加传递的结束时间;并在递归成员中检查是否使用固定的60分钟(如果知道尚未达到结束时间)或使用从结束时间开始的实际分钟。
我的示例时段包括跨越午夜,不到一小时的时段,并且开始于一小时的第一分钟-结束于一小时的第一分钟,无论如何,以我的计算无论如何,该小时连续一行,分钟数为零。如果您不想看到它,可以轻松过滤掉它。
答案 1 :(得分:0)
您的帖子中还不清楚您要如何处理非零秒分量(舍入和/或截断的组合)。无论如何,一旦达成一整套无矛盾的规则,就可以轻松进行编码。
除此之外,您的问题包括两部分:确定每个ID(每个活动或事件)的正确时数,以及该事件在该小时中的持续时间。在下面的查询中,使用CONNECT BY
分层技术,我将小时和持续时间生成为一天到秒的间隔。正如我说的那样,一旦您阐明了舍入规则,就可以将其转换为分钟(0到60之间)。
with
your_table (id, start_time, end_time) as (
select 1, timestamp '2019-01-09 17:04:34', timestamp '2019-01-09 19:55:03'
from dual union all
select 2, timestamp '2019-01-09 23:47:01', timestamp '2019-01-10 02:05:03'
from dual union all
select 3, timestamp '2019-01-09 18:01:01', timestamp '2019-01-09 18:02:07'
from dual union all
select 4, timestamp '2019-01-09 13:00:00', timestamp '2019-01-09 14:00:01'
from dual
)
select id,
trunc(start_time, 'hh') + interval '1' hour * (level - 1) as hr,
case when level = 1 and connect_by_isleaf = 1
then end_time - start_time
when level = 1
then trunc(start_time, 'hh') + interval '1' hour - start_time
when connect_by_isleaf = 1
then end_time - trunc(end_time, 'hh')
else interval '1' hour
end as duration
from your_table
connect by trunc(start_time, 'hh') + interval '1' hour * (level - 1) < end_time
and prior id = id
and prior sys_guid() is not null
;
输出:
ID HR DURATION
---------- ------------------- -------------------
1 2019-01-09 17:00:00 +00 00:55:26.000000
1 2019-01-09 18:00:00 +00 01:00:00.000000
1 2019-01-09 19:00:00 +00 00:55:03.000000
2 2019-01-09 23:00:00 +00 00:12:59.000000
2 2019-01-10 00:00:00 +00 01:00:00.000000
2 2019-01-10 01:00:00 +00 01:00:00.000000
2 2019-01-10 02:00:00 +00 00:05:03.000000
3 2019-01-09 18:00:00 +00 00:01:06.000000
4 2019-01-09 13:00:00 +00 01:00:00.000000
4 2019-01-09 14:00:00 +00 00:00:01.000000