2017-10-24 1 views
0

Ich habe eine Tabelle events wie folgt benannt:Wie bekomme ich die maximale Anzahl gleichzeitiger Ereignisse in postgresql?

id: int 
source_id: int 
start_datetime: timestamp 
end_datetime: timestamp 

Diese Ereignisse Überschneidungen haben könnte, und ich möchte maximale Anzahl wissen Ereignisse sich überlappender, die über eine Zeitspanne aufgetreten sind. Zum Beispiel in einer Situation wie diese:

id | source_id | start_datetime  | end_datetime 
---------------------------------------------------------- 
1 | 23  | 2017-1-1T10:20:00 | 2017-1-1T10:40:00 
1 | 42  | 2017-1-1T10:30:00 | 2017-1-1T10:35:00 
1 | 11  | 2017-1-1T10:37:00 | 2017-1-1T10:50:00 

Die Antwort ist 2, weil höchstens zwei Veranstaltungen um 10.30 Uhr bis 10.35 Uhr überlappen.
Ich bin mit Postgres 9.6

+0

eine Zeitspanne ist ein Eingang? –

+0

aus Gründen der Einfachheit, es für jede Abfrage konstant halten – sazary

+0

Ich weiß nicht, ob es so viel Unterschied macht, aber betrachten Sie es 9.6 – sazary

Antwort

0

Ich bin nicht ganz sicher, wie die id und source_id Säule behandelt werden soll, sondern von Ihrer Beschreibung, so etwas wie die vielleicht:

select e1.source_id, 
     count(distinct e2.source_id) as overlap_count, 
     array_agg(e2.source_id) as overlap_events 
from events e1 
    join events e2 
    on e1.source_id <> e2.source_id 
    and (e1.start_datetime, e1.end_datetime) overlaps (e2.start_datetime, e2.end_datetime) 
group by e1.source_id 
order by overlap_count desc; 

Ihre Beispieldaten gegeben, dass die liefert folgende:

source_id | overlap_count | overlap_events 
----------+---------------+--------------- 
     23 |    2 | {42,11}  
     11 |    1 | {23}   
     42 |    1 | {23}   

um nur die maximale Zeilen bekommen Sie eine limit 1 auf die Abfrage hinzufügen könnte.

Weitere (wahrscheinlich langsamer) Option, wenn Sie die komplette Zeile aus der Tabelle Ereignisse:

select e1.id, e1.source_id, e1.start_datetime, e1.end_datetime, 
     (select count(*) 
     from events e2 
     where e2.source_id <> e1.source_id 
      and (e1.start_datetime, e1.end_datetime) overlaps (e2.start_datetime, e2.end_datetime) 
     ) as overlap_count 
from events e1 
order by overlap_count desc; 

Eine weitere Option ist range types und die && Operator verwenden statt overlaps:

select e1.source_id, 
     count(distinct e2.source_id) as overlap_count, 
     array_agg(e2.source_id) as overlap_events 
from events e1 
    join events e2 on e1.source_id <> e2.source_id 
      and tsrange(e1.start_datetime, e1.end_datetime,'[]') && tsrange(e2.start_datetime, e2.end_datetime, '[]') 
group by e1.source_id 
order by overlap_count desc; 
+0

Ein Ereignis kann viele andere überlappen, aber wenn sie alle disjunktive maximale Anzahl gleichzeitiger Ereignisse werden sei 2. – klin

1

Hier ist die Idee: Zählen Sie die Anzahl der Starts und subtrahieren Sie die Anzahl der Stopps. Das gibt den Nettobetrag zu jedem Zeitpunkt an. Der Rest ist nur Aggregation:

Die Unterabfrage zeigt die Anzahl der überlappenden Ereignisse zu jeder Zeit.

Sie können den Zeitrahmen wie erhalten:

select dte, next_dte, concurrent 
from (select dte, sum(sum(inc)) over (order by dte) as concurrent, 
      lead(dte) over (partition by dte) as next_dte 
     from e 
    ) e 
order by concurrent desc 
fetch first 1 row only; 
Verwandte Themen