我有一个数据库,可在员工登录到不同状态时提供信息,但问题是,它将整个持续时间与15分钟间隔相关联,而不管持续时间是否长于15分钟间隔,这会导致在创建此计算时出现差异数据。
样本数据集:
**ID | Date | Start Time | End Time | Secs | State | SubState**
10001 | 18/MAR/20 | 09:06:41.000000000 AM | 09:09:31.000000000 AM | 170 | Ready | Ready
10001 | 18/MAR/20 | 09:09:31.000000000 AM | 09:44:41.000000000 AM | 2110 | NotReady | Busy
10001 | 18/MAR/20 | 09:44:41.000000000 AM | 09:51:31.000000000 AM | 410 | NotReady | ACW
10001 | 18/MAR/20 | 09:51:31.000000000 AM | 09:54:25.000000000 AM | 174 | NotReady | Busy
10001 | 18/MAR/20 | 09:54:25.000000000 AM | 09:55:00.000000000 AM | 35 | NotReady | ACW
所需结果:
**ID | Date | 15 Int | Secs | State | SubState**
10001 | 18/MAR/20 | 09:00 AM | 170 | Ready | Ready
10001 | 18/MAR/20 | 09:00 AM | 329 | NotReady | Busy
10001 | 18/MAR/20 | 09:15 AM | 900 | NotReady | Busy
10001 | 18/MAR/20 | 09:30 AM | 881 | NotReady | Busy
10001 | 18/MAR/20 | 09:30 AM | 19 | NotReady | ACW
10001 | 18/MAR/20 | 09:45 AM | 391 | NotReady | ACW
10001 | 18/MAR/20 | 09:45 AM | 174 | NotReady | Busy
10001 | 18/MAR/20 | 09:45 AM | 35 | NotReady | Busy
在Oracle SQL中最简单的方法是什么?
这类似于我以前见过的问题。我进行的示例查询基于每个15分钟的时间段并分析与之重叠的所有时间间隔。尝试以其他方式进行操作会造成混淆。
根据评论,我不确定您的真实数据是否可能每15分钟有重复的状态/子状态组合,如果是这样,下面的查询可能需要进行修改以正确汇总内容。
[我注意到,在“所需结果”的最后一行中,您的子状态为“忙”,而在数据集中,此35秒间隔显示为“ ACW”。我以为这只是一个错误,我的结果具有后一个值。
查询概要:
首先,我们创建mytable2,它从“ mytable”中获取示例数据,并将开始和结束时间转换为Oracle日期。
最后,实际查询是一个四向并集,其中每个分支都连接q2和mytable2。
with mytable2 as (
select ID, date_ as "Date",
cast(to_timestamp(date_ || ' ' || START_TIME, 'dd/mon/yy HH:MI:SS.FF AM') as date) "Start Time",
cast(to_timestamp(date_ || ' ' || END_TIME, 'dd/mon/yy HH:MI:SS.FF AM')as date) "End Time",
secs,
state,
substate
from mytable
), q1 as (
select trunc(min("Start Time"), 'hh') as m1, trunc(max("End Time")+1/24, 'hh') as m2
from mytable2
),
q2 as (
select m1 + (rownum-1)/24/4 as b1, m1 + rownum/24/4 as b2
from q1, dual
connect by rownum <= (m2-m1)*24*4
)
select "ID", "Date", "15 Int", "Secs", "State", "SubState" from (
select ID, "Date", "Start Time", to_char(b1, 'HH:MI AM') as "15 Int", secs as "Secs", state as "State", substate as "SubState" from mytable2 m
join
q2 on "Start Time" >= b1 and "End Time" <= b2
union
select ID, "Date",b1 as "Start Time", to_char(b1, 'HH:MI AM') as "15 Int", 900 , state, substate from mytable2 m
join
q2 on "Start Time" < b1 and "End Time" > b2
union
select ID, "Date",b1 as "Start Time", to_char(b1, 'HH:MI AM') as "15 Int", round(("End Time" - b1)*24*3600,0) , state, substate from mytable2 m
join
q2 on "Start Time" < b1 and ("End Time" between b1 and b2)
union
select ID, "Date","Start Time", to_char(b1, 'HH:MI AM') as "15 Int", round((b2-"Start Time")*24*3600,0), state, substate from mytable2 m
join
q2 on ("Start Time" between b1 and b2 )and "End Time" > b2
) q
order by q.ID, q."Start Time"
+-------+-----------+----------+------+----------+----------+
| ID | Date | 15 Int | Secs | State | SubState |
+-------+-----------+----------+------+----------+----------+
| 10001 | 18/MAR/20 | 09:00 AM | 170 | Ready | Ready |
| 10001 | 18/MAR/20 | 09:00 AM | 329 | NotReady | Busy |
| 10001 | 18/MAR/20 | 09:15 AM | 900 | NotReady | Busy |
| 10001 | 18/MAR/20 | 09:30 AM | 881 | NotReady | Busy |
| 10001 | 18/MAR/20 | 09:30 AM | 19 | NotReady | ACW |
| 10001 | 18/MAR/20 | 09:45 AM | 391 | NotReady | ACW |
| 10001 | 18/MAR/20 | 09:45 AM | 174 | NotReady | Busy |
| 10001 | 18/MAR/20 | 09:45 AM | 35 | NotReady | ACW |
+-------+-----------+----------+------+----------+----------+
我使用下表进行测试:
create table mytable as select '10001' ID,'18/MAR/20' DATE_, '09:06:41.000000000 AM' START_TIME,'09:09:31.000000000 AM' END_TIME,170 secs, 'Ready' State, 'Ready' substate from dual union all select '10001' ID,'18/MAR/20' DATE_, '09:09:31.000000000 AM' START_TIME,'09:44:41.000000000 AM' END_TIME,2110 secs, 'NotReady' State, 'Busy' substate from dual union all select '10001' ID,'18/MAR/20' DATE_, '09:44:41.000000000 AM' START_TIME,'09:51:31.000000000 AM' END_TIME,410 secs, 'NotReady' State, 'ACW' substate from dual union all select '10001' ID,'18/MAR/20' DATE_, '09:51:31.000000000 AM' START_TIME,'09:54:25.000000000 AM' END_TIME,174 secs, 'NotReady' State, 'Busy' substate from dual union all select '10001' ID,'18/MAR/20' DATE_, '09:54:25.000000000 AM' START_TIME,'09:55:00.000000000 AM' END_TIME,35 secs, 'NotReady' State, 'ACW' substate from dual
+-------+-----------+-----------------------+-----------------------+------+----------+----------+
| ID | DATE_ | START_TIME | END_TIME | SECS | STATE | SUBSTATE |
+-------+-----------+-----------------------+-----------------------+------+----------+----------+
| 10001 | 18/MAR/20 | 09:06:41.000000000 AM | 09:09:31.000000000 AM | 170 | Ready | Ready |
| 10001 | 18/MAR/20 | 09:09:31.000000000 AM | 09:44:41.000000000 AM | 2110 | NotReady | Busy |
| 10001 | 18/MAR/20 | 09:44:41.000000000 AM | 09:51:31.000000000 AM | 410 | NotReady | ACW |
| 10001 | 18/MAR/20 | 09:51:31.000000000 AM | 09:54:25.000000000 AM | 174 | NotReady | Busy |
| 10001 | 18/MAR/20 | 09:54:25.000000000 AM | 09:55:00.000000000 AM | 35 | NotReady | ACW |
+-------+-----------+-----------------------+-----------------------+------+----------+----------+
WITH time_intervals AS
(
SELECT s.min_date+(15*(LEVEL-1)/1440) AS INTERVAL_START,
s.min_date+(15*LEVEL/1440) AS INTERVAL_END
FROM (SELECT MIN(TO_DATE(u.event_date, 'DD/MON/YY')) AS MIN_DATE,
MAX(TO_DATE(u.event_date, 'DD/MON/YY')) AS MAX_DATE
FROM user_data u) s
CONNECT BY LEVEL <= (s.max_date-s.min_date+1)*96 --96 is the number of 15 min intervals in a day
)
SELECT u.id AS ID,
ti.interval_start,
SUM((LEAST(ti.interval_end, u.end_time) - GREATEST(ti.interval_start, u.start_time))*86400) AS SECONDS,
u.state,
u.substate
FROM time_intervals ti
INNER JOIN (SELECT ud.id,
TO_DATE(ud.event_date||' '||ud.start_time, 'DD/MON/YY HH:MI:SS PM') AS START_TIME,
TO_DATE(ud.event_date||' '||ud.end_time, 'DD/MON/YY HH:MI:SS PM') AS END_TIME,
ud.state, ud.substate
FROM user_data ud) u ON GREATEST(ti.interval_start, u.start_time) < LEAST(ti.interval_end, u.end_time)
GROUP BY u.id, ti.interval_start, u.state, u.substate;
首先,我们计算出您表中各天的15分钟间隔。如果要限制报告,只需将此CTE更改为仅考虑要报告的天数即可。然后,我们根据表中与给定间隔重叠的记录将CTE加入到您现有的数据中。每个重叠间隔乘以86400(一天的秒数)即可得出结果。最后,我们使用聚合函数总和来说明在同一15分钟间隔内具有相同ID,状态和子状态的多个事件。我创建了一个SQLFiddle以供您检查(Link)。