2015-11-12 34 views
3

我想弄清楚一種方法,可以識別表中的事件記錄同時發生的時間。Oracle SQL - 計算併發事件數

例如,考慮到我有一個名爲EVENTS表中的Oracle數據庫::

|EVENT_UUID|HOST_NAME|START_TM|END_TM| 

|1|host1|12-JUN-15 01.31.04.092000000 PM|12-JUN-15 01.55.58.716000000 PM| 
|2|host2|15-JUN-15 10.02.45.494000000 AM|15-JUN-15 01.12.18.257000000 PM| 
|3|host3|17-JUN-15 03.19.48.506000000 PM|17-JUN-15 03.51.59.874000000 PM| 
|4|host4|18-JUN-15 09.24.36.602000000 PM|NULL| 
|5|host5|18-JUN-15 12.32.43.109000000 PM|19-JUN-15 01.22.32.412000000 PM| 

我知道我可以找到所有在指定日期範圍內開始做這樣的事情,該事件::

SELECT * 
FROM EVENTS 
WHERE START_TM BETWEEN TO_DATE('2015-JUN-11', 'YYYY-MON-DD') AND TO_DATE('2015-JUN-13', 'YYYY-MON-DD'); 

但是,這隻給我所有在該範圍內開始的事件。

最後,我想能夠運行報告並檢查之類的東西下面,

  • 「發生在一天的併發事件的數量。」 「
  • 」一小時內發生的併發事件的數量。「

有沒有人知道一種方法可以幫助我確定事件是否同時發生?

+0

[確定是否兩個日期範圍重疊](http://stackoverflow.com/questions/325933/determine-whether-two-date-ranges-overlap)這是有關日期重疊的最佳解釋 –

+0

'NULL'對'END_TM'意味着什麼? –

+0

@ShannonSeverance這意味着事件尚未結束。 這些事件基本上代表了用戶許可證的消耗,並且我想跟蹤在任何給定時間有多少許可證正在使用。 – Chiefwarpaint

回答

2

你可以通過使用相對簡單的技術來計算併發事件的數量:累積聚合。這個想法是計算啓動和停止的次數。那麼累計數就是併發值的數量。

select tm, sum(isstart) as numstarts, sum(isstop) as numstops, 
     (sum(sum(isstart)) over (order by tm nulls last) - 
     sum(sum(isstop)) over (order by tm nulls last) 
     ) as NumConcurrent 
from ((select start_tm as tm, 1 as isstart, 0 as isstop from events 
    ) union all 
     (select stop_tm, 0 as isstart, 1 as isstop from events 
    ) 
    ) e 
group by tm; 

這給你併發事件的數據每次數量(無論是開始或結束時間。然後,您可以使用where條款和order by/fetch first提取一天或一小時的最大值或聚合

+0

感謝Gordon。雖然問題。出於某種原因,當我以您的示例運行時,我收到的記錄中包含的START_TM值實際上並不存在於Db中。 ' 「TM」 \t 「NUMSTARTS」 \t 「NUMSTOPS」 \t 「NUMCONCURRENT」 12-JUN-15 11.16.42.811000000 AM \t -JUN-15 11.17.15.001000000 AM \t 12-JUN-15 12.01.30.957000000 PM \t 12-JUN-15 12.07.55.972000000 PM \t -JUN-15 12.51.57.551000000 PM \t -JU N-15 01.27.01.938000000 PM 12-JUN-15 01.30.45.121000000 PM ' 如何可能發生的任何想法?我將發佈我在下一條評論中寫的SQL。 SO正在限制我。 :) – Chiefwarpaint

+0

'select tm,sum(isstart)as numstarts,sum(isstop)as numstops, (sum(sum(isstart))over(by tm nulls last) - sum(isstop)over (選擇e1.START_TM作爲tm,1作爲isstart,0作爲isstop從EVENTS e1 )union all (select e2.END_TM,0 as isstart,1 as isstop from EVENTS ('2015-JUN-11','YYYY-MON-DD')和TO_DATE('2015-JUN-13','YYYY-MON-DD') 分組依據tm order by tm;' – Chiefwarpaint

+0

這是一個非常有趣的技術。獲取我並不簡單,但我喜歡。 –

0

使用類似於以下謂詞:

where start_tm <= TO_DATE('2015-JUN-13 23:59:59', 'YYYY-MON-DD HH24:MI:SS') 
    and (end_tm is null or TO_DATE('2015-JUN-11 00:00:00', 'YYYY-MON-DD HH24:MI:SS') <= end_tm) 

這將拾起你的報告期結束前開始,你的報告期開始後結束的所有事件。

它不會選擇報告期開始前或報告期結束後開始的事件。

1

我認爲你需要加入表本身,並得到所有的事件,其中的2個事件的範圍:

event1.start between event2.start and event2.end 
OR 
event1.end between event2.start and event2.end 
OR 
event1.start < event2.start and event1 > event2.end 
AND CHECK THAT 
event.end can be null 

to filter the data - see `where` in query below 
to count number of events - use count(*) over() 

測試數據

insert into events(EVENT_UUID,HOST_NAME,START_TM,END_TM) 
    values (1,'host1',to_date('12-JUN-15 01.31.04','dd-mon-yy hh24.mi.ss'),to_date('12-JUN-15 01.55.58','dd-mon-yy hh24.mi.ss')) 

insert into events(EVENT_UUID,HOST_NAME,START_TM,END_TM) 
    values (2,'host2',to_date('15-JUN-15 10.02.45','dd-mon-yy hh24.mi.ss'),to_date('15-JUN-15 11.12.18','dd-mon-yy hh24.mi.ss')); 

insert into events(EVENT_UUID,HOST_NAME,START_TM,END_TM) 
    values (3,'host3',to_date('17-JUN-15 03.19.48','dd-mon-yy hh24.mi.ss'),to_date('17-JUN-15 03.51.59','dd-mon-yy hh24.mi.ss')); 

insert into events(EVENT_UUID,HOST_NAME,START_TM,END_TM) 
    values (4,'host4',to_date('18-JUN-15 09.24.36','dd-mon-yy hh24.mi.ss'),null); 

insert into events(EVENT_UUID,HOST_NAME,START_TM,END_TM) 
    values (5,'host5',to_date('18-JUN-15 12.32.43','dd-mon-yy hh24.mi.ss'),to_date('19-JUN-15 01.22.32','dd-mon-yy hh24.mi.ss')); 

insert into events(EVENT_UUID,HOST_NAME,START_TM,END_TM) 
    values (6,'host6',to_date('18-JUN-15 12.45.43','dd-mon-yy hh24.mi.ss'),to_date('19-JUN-15 01.01.32','dd-mon-yy hh24.mi.ss')); 

insert into events(EVENT_UUID,HOST_NAME,START_TM,END_TM) 
    values (7,'host7',to_date('12-JUN-15 01.32.04','dd-mon-yy hh24.mi.ss'),to_date('12-JUN-15 02.55.58','dd-mon-yy hh24.mi.ss')) 

查詢:

select ev1.event_uuid, ev2.event_uuid 
    , ev1.start_tm, ev1.end_tm 
    , ev2.start_tm, ev2.end_tm 
    ,count(*) over() as total_count 
from events ev1 
    inner join events ev2 
    on ((ev1.start_tm between ev2.start_tm and nvl(ev2.end_tm, sysdate)) 
    or (nvl(ev1.end_tm,sysdate) between ev2.start_tm and nvl(ev2.end_tm, sysdate)) 
    or (ev2.start_tm < ev1.start_tm and nvl(ev1.end_tm,sysdate) < nvl(ev1.end_tm, sysdate))) 
     and ev1.event_uuid != ev2.event_uuid 
    where to_date('18.06.2015 13', 'dd.mm.yyyy hh24') between ev1.start_tm and nvl(ev1.end_tm,sysdate) 
order by 3,4 

    EVENT_UUID EVENT_UUID START_TM END_TM START_TM END_TM TOTAL_COUNT 
1 5 4 18/06/2015 12:32:43 19/06/2015 01:22:32 18/06/2015 09:24:36  3 
2 6 5 18/06/2015 12:45:43 19/06/2015 01:01:32 18/06/2015 12:32:43 19/06/2015 01:22:32 3 
3 6 4 18/06/2015 12:45:43 19/06/2015 01:01:32 18/06/2015 09:24:36  3 
+0

在OP的數據中,時間部分包括AM/PM指定。您在開始記錄樣本數據創建事件2時放棄了這些。 – Sentinel