sql - oracle sql查询时间段集合并集
问题描述
我有一个包含以下表格的 oracle 数据库。如何计算每个房间的使用时间?每个房间的时间段可能会重叠,表格结构如下。</p>
t_room_electricity
+------------+--------------------+--------------------+
| roomcode | starttime | endtime |
+------------+--------------------+--------------------+
| 123 | 2019/5/10 10:00:00 | 2019/5/10 11:30:00 |
| 123 | 2019/5/10 10:30:00 | 2019/5/10 11:00:00 |
| 456 | 2019/5/10 11:00:00 | 2019/5/10 12:00:00 |
| 456 | 2019/5/10 13:00:00 | 2019/5/10 14:00:00 |
| 456 | 2019/5/10 13:30:00 | 2019/5/10 15:00:00 |
| 789 | 2019/6/10 14:22:00 | 2019/6/10 14:26:00 |
| 789 | 2019/6/10 14:31:00 | 2019/6/10 14:36:00 |
| 886 | 2019/6/10 14:32:00 | 2019/6/10 14:35:00 |
+------------+--------------------+--------------------+
解决方案
更新答案以迎合 OP 提到的情况。
使用 MATCH_RECOGNIZE
with data
as (
select *
from t_room_electricity
match_recognize(
partition by roomcode
order by starttime
measures
first(starttime) f_starttime
,last(starttime) l_starttime
,first(endtime) f_endtime
,last(endtime) l_endtime
,min(starttime) as min_starttime
,max(endtime) as max_endtime
,match_number() as mn
,classifier() as cls
pattern(strt group1*)
define group1
as starttime<first(endtime)
)
)
select roomcode
,round(sum((max_endtime-min_starttime)*24*60)) as diff_in_minutes
from data
group by roomcode
请参阅输出 https://dbfiddle.uk/?rdbms=oracle_18&fiddle=783140ede5dfbf8088a6ce77232ecef7
使用 SQL
select x.roomcode
,count(distinct x.minutes_worked)
from (
select a.roomcode
,a.starttime
,a.endtime
,a.starttime + lvl/24/60 as minutes_worked
from t_room_electricity a
join (select level as lvl
from dual
connect by level<=24*60
)b
on b.lvl<=to_number((a.endtime-a.starttime)*24*60)
)x
group by x.roomcode
见输出.. https://dbfiddle.uk/?rdbms=oracle_11.2&fiddle=2add9344f1335376b2fe32df21f769d6
更新了答案以迎合重叠,(基于新记录集)
456 | 2019/5/10 11:00:00 | 2019/5/10 12:00:00 |
456 | 2019/5/10 13:00:00 | 2019/5/10 14:00:00 |
456 | 2019/5/10 13:30:00 | 2019/5/10 15:00:00 |
456 | 2019/5/10 13:45:00 | 2019/5/10 15:05:00 |
考虑重叠以下查询可以达到预期的结果
select roomcode
,sum(round(time_in_minutes))
from (
select roomcode
,eventdate
,case when start_flag=1
and (lag(start_flag) over(partition by roomcode order by eventdate asc) = 0
or lag(start_flag) over(partition by roomcode order by eventdate asc) is null)
then null
else (eventdate
-
lag(eventdate) over(partition by roomcode order by eventdate asc)
)*24*60
end as time_in_minutes
from (
select roomcode,starttime as eventdate,1 as start_flag from t_room_electricity
union all
select roomcode,endtime as eventdate,0 as start_flag from t_room_electricity
)x
)y
group by roomcode
+----------+-----------------------------+
| ROOMCODE | SUM(ROUND(TIME_IN_MINUTES)) |
+----------+-----------------------------+
| 123 | 90 |
| 456 | 185 |
| 789 | 9 |
| 886 | 3 |
+----------+-----------------------------+
这首先创建了一个内部块,它将每个 eventdatetime 存储到一个名为 EventDate 的列中。然后步骤是检查前一个事件是否是封闭边界(即 start_flag = 1),如果是,则开始计数,否则继续计算前一个事件之间的差异(以分钟为单位)
在此之后,结果按房间代码分组,并总结了 time_in_minutes
https://dbfiddle.uk/?rdbms=oracle_11.2&fiddle=650b4f0ad7304d7f44e7fabbca160a90
旧答案 您可以通过使用 group by 表达式来实现这一点,如下所示
select roomcode,sum((endtime-starttime)*24*60) as diff_in_minutes
from t_room_electricity
group by roomcode
+----------+-----------------+
| ROOMCODE | DIFF_IN_MINUTES |
+----------+-----------------+
| 123 | 120 |
| 789 | 9 |
| 456 | 210 |
| 886 | 3 |
+----------+-----------------+
请参阅 dbfiddle 链接。 https://dbfiddle.uk/?rdbms=oracle_11.2&fiddle=16fd05220157fd274cf0fab4e61c8802
推荐阅读
- shiny - R Shiny:有关闭反应组件的选项吗?
- machine-learning - 如何设计 MLP 神经网络来预测成本?
- haskell - 如何更改 Threepenny GUI 中的按钮布局和位置?
- html - IIS Url Rewrite 导致 403 Forbidden
- salesforce - 如何使用nexmo api从网络浏览器拨打电话?
- java - 无法在 Ms Word 中使用 acrofields 为表单设置字段值
- docker - docker-compose 重启的区别
和泊坞窗重新启动 ? - mysql - 局部变量求和前列
- mysql - SQL 中的更新替换分号获取语法错误
- python - 寻找两个圆的交点