Oracle-将持续时间与不同的15分钟间隔相关联

问题描述 投票:0回答:2

我有一个数据库,可在员工登录到不同状态时提供信息,但问题是,它将整个持续时间与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中最简单的方法是什么?

sql oracle time oracle11g oracle11gr2
2个回答
0
投票

这类似于我以前见过的问题。我进行的示例查询基于每个15分钟的时间段并分析与之重叠的所有时间间隔。尝试以其他方式进行操作会造成混淆。

根据评论,我不确定您的真实数据是否可能每15分钟有重复的状态/子状态组合,如果是这样,下面的查询可能需要进行修改以正确汇总内容。

[我注意到,在“所需结果”的最后一行中,您的子状态为“忙”,而在数据集中,此35秒间隔显示为“ ACW”。我以为这只是一个错误,我的结果具有后一个值。

查询概要:

  • 首先,我们创建mytable2,它从“ mytable”中获取示例数据,并将开始和结束时间转换为Oracle日期。

  • [[然后,我们创建q1,它具有一行,其中m1列位于数据之前的小时,而m2列位于数据之后的小时。
  • 然后,我们创建q2,该q2是我们感兴趣的所有15分钟间隔的起点。每当需要一些序号时,使用connect by ... rownum是常见的模式。

最后,实际查询是一个四向并集,其中每个分支都连接q2和mytable2。

    Branch#1是指间隔完全在15分钟内的区间。
  • 分支2是15分钟的时间段完全在间隔内的位置。
  • Branch#3是间隔在15分钟之前开始并在15分钟之内结束的位置。
  • Branch#4是间隔在15分钟段之内开始和结束的位置。
  • 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      |
    +-------+-----------+-----------------------+-----------------------+------+----------+----------+
    

  • 0
    投票
    我认为您的问题有一个更简单的答案。尽管我在评论中同意其他人的意见,即您应该真正更改日期的存储方式,但我现在仍然坚持使用。以下查询应满足您的需求:

    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)。

    © www.soinside.com 2019 - 2024. All rights reserved.