Reputation: 683
I'm trying to figure out a way that I can identify when event records in a table occurred at the same time.
For instance, consider that I have a table called EVENTS
in an Oracle Database::
|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|
I know that I can find all of the events that started within a given date range by doing something like this::
SELECT *
FROM EVENTS
WHERE START_TM BETWEEN TO_DATE('2015-JUN-11', 'YYYY-MON-DD') AND TO_DATE('2015-JUN-13', 'YYYY-MON-DD');
But that only gives me all the events that started in that range.
Ultimately, I would like to be able to run reports and check things like the following,
Does anybody know of an approach that would help me identify when events were concurrently happening?
Upvotes: 4
Views: 770
Reputation: 2615
I think you need join the table to itself and get all events where the range of 2 events:
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 ()
test data
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'))
query:
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
Upvotes: 1
Reputation: 6449
Use a predicate similar to the following:
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)
this will pick up all events which started before the end of your reporting period and ended after the start of your reporting period.
It will not pick up events which ended before the start of your reporting period or started after the end of your reporting period.
Upvotes: 0
Reputation: 1270583
You can calculate the number of concurrent events by using a relatively simple technique: cumulative aggregation. The idea is to count the number of starts and stops. Then the cumulative number is the number of concurrent values.
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;
This gives you the number of concurrent events for each time in the data (either a start or end time. You can then extract the maximum value for a day or hour using a where
clause and order by
/fetch first
or aggregation.
Upvotes: 3