2016-04-01 11 views
2

durch jede Reihe von looping habe ich eine Tabelle mit Stromausfall Informationen, die wie folgt ausseheneine Reihe basierte Lösung zu finden, statt in SQL

KEY  OUTAGE TIME  POWER LINE ID 
1  1/1 2:30 pm  75 
2  1/5 4:00 pm  247 
3  1/5 6:00 pm  247 
4  1/3 8:00 am  11 

KEY ist nur der Primärschlüssel der Tabelle. Die Ausfallzeit sagt uns, wann der Ausfall aufgetreten ist, und die Stromleitungs-ID ist nur die Identifikationsnummer der Leitung, an der der Ausfall aufgetreten ist.

ich eine zweite Tabelle mit Zählerinformationen haben, die wie folgt aussieht,

event_ID  event_timestamp  event_info  POWER LINE ID 
44   1/5 1:45 pm   power on   247 
45   1/5 1:45 pm   power on   247 
46   1/5 3:45 pm   fault detected 247 
47   1/5 3:55 pm   power off   247 
48   1/5 3:58 pm   power off   247 
49   1/5 5:15 pm   power on   247 
50   1/5 5:45 pm   power off   247 
51   1/5 5:50 pm   power off   247 
52   1/5 5:55 pm   power off   247 
53   1/5 5:59 pm   power off   247 

Ziel ist die folgende: Für jeden Ausfall, wählen Sie die alle Zähler Ereignisse, die vor dem Ausfallzeit auf dieser Stromleitung passiert und nach dem letzten "Power-On" -Signal, das auf dieser Stromleitung aufgetreten ist.

Zum Beispiel, für Ausfall # 2, würden wir alle Zähler Ereignisse vor 1/5 16:00 Uhr (Ausfallzeit), aber alle Ereignisse, die nach 1/5 13:45 Uhr aufgetreten sind, seit diesem ist das letzte "Power On" -Signal, das vor dem Ausfall aufgetreten ist. Für den Ausfall # 3 würden wir uns alle Ereignisse anschauen, die vor dem 15.5. 18:00 Uhr (Ausfallzeit) aufgetreten sind, aber nach dem 15.05.15 Uhr, da dies das letzte "Power-On" -Signal ist, das aufgetreten ist vor der Ausfallzeit.

Ich habe dies mit einem Cursor gemacht, der die Ausfalltabelle durchläuft und eine gespeicherte Prozedur aufruft, die die gewünschten Ereignisse aus der Ereignistabelle auswählt, aber diese Tabellen sind sehr groß und der Cursor dauert zu lange. Ich würde gerne wissen, wie man sich an dieses Problem annähern kann. Vielen Dank!

EDIT: Sorry, ich habe völlig vergessen, die Beispielausgabe zu veröffentlichen. Hier ist es.

EDIT (wieder): Ich suche nach einer Lösung für diese in Oracle. Es tut mir leid für die Änderungen, zum ersten Mal hier eine Frage zu stellen.

+0

Ich habe mehrdeutige DBMS-Tags aus der Bearbeitung entfernt, die die richtige enthalten würden. Die Antworten können für verschiedene Datenbanksysteme spezifisch sein. –

+0

Verstehe ich diese Frage? Möchten Sie für jede "Ausfall" -Reihe in Ihrer Tabelle alle "Ereignis" -Reihen ** außer denen mit Zeitstempeln zwischen dem Ausfallzeitstempel und dem größten "Power-On" -Zeitstempel auswählen? Eine weitere Frage: Was sind die Datentypen in den Tabellen der Spalten 'OUTAGE TIME' und 'event_timestamp'? –

+1

@jpw Ich habe die Beispielausgabe hinzugefügt – user6147110

Antwort

2

Ich löse das Problem mit SQL Server, also bedeutet Temp-Tabelle.

unter Tabellen und Daten Unter der Annahme,

create table #outage ([key] int, outage_time datetime, power_line int) 

insert into #outage values 
(1,  '2015/1/1 2:30 pm',  75), 
(2,  '2015/1/5 4:00 pm', 247), 
(3,  '2015/1/5 6:00 pm', 247), 
(4,  '2015/1/3 8:00 am',  11) 

create table #even (event_ID int , event_time datetime, 
        event_info varchar(20), power_line int) 

insert into #even values 
(44,   '2015/1/5 1:45 pm'   ,'power on'   ,247), 
(45,   '2015/1/5 1:45 pm'   ,'power on'   ,247), 
(46,   '2015/1/5 3:45 pm'   ,'fault detected' ,247), 
(47,   '2015/1/5 3:55 pm'   ,'power off'   ,247), 
(48,   '2015/1/5 3:58 pm'   ,'power off'   ,247), 
(49,   '2015/1/5 5:15 pm'   ,'power on'   ,247), 
(50,   '2015/1/5 5:45 pm'   ,'power off'   ,247), 
(51,   '2015/1/5 5:50 pm'   ,'power off'   ,247), 
(52,   '2015/1/5 5:55 pm'   ,'power off'   ,247), 
(53,   '2015/1/5 5:59 pm'   ,'power off'   ,247) 

Dies ist die Abfrage:

select o.[key], e.event_ID, o.power_line 
from #outage o 
    inner join #even e on e.power_line = o.power_line 
    and e.event_time < o.outage_time 
    and e.event_time > (select max(event_time) from #even 
         where power_line = o.power_line 
          and event_time < o.outage_time 
          and event_info = 'power on') 
+0

Oh, ich sehe, wie Sie es gemacht haben, zuerst verbindet der Join die Ausfall-IDs mit den Ereignissen basierend auf der Stromleitungs-ID, und dann wählen Sie die gewünschten Ereignisse basierend auf den Kriterien aus. Es ist so viel schneller als der Cursor, vielen Dank für die Hilfe! – user6147110

1

Try this:

SELECT power_outage.key, 
     meters.event_id, 
     power_outage.power_line_id 
FROM power_outage 
JOIN meter_info meters 
    ON power_outage.power_line_id = meters.power_line_id 
AND meters.event_timestamp < power_outage.outage_time 
WHERE meters.event_timestamp > (SELECT MAX(lpo.event_timestamp) 
           FROM meter_info lpo -- LastPowerOn 
           WHERE lpo.power_line_id = power_outage.power_line_id 
            AND lpo.event_info = 'power on' 
            AND lpo.event_timestamp < power_outage.outage_time); 

Die 'JOIN', um alle Elemente wird so weit wie sie aufgetreten vor der Ausfallzeit, während die Bedingung die Elemente des zuletzt eingeschalteten Geräts filtert.

+0

Ich bemerkte meine Antwort ist mehr oder weniger gleich zu der FLICKER gepostet, kurz bevor ich es getan habe. Ich habe diese Antwort erst gesehen, nachdem ich meine gepostet habe. –

+0

Vielen Dank für die Hilfe, ich schätze es sehr! – user6147110

1

Dies ist ein wenig länger Abfrage CTE beteiligt, aber einfacher auf einen Schritt-für-Schritt-Basis zu verstehen:

WITH events_before_outage AS (
select 
    ot.key, ot.outage_time, ot.power_line_id, mi.event_id, mi.event_timestamp, mi.event_info 
from outage_table ot 
left join meter_information mi 
    on ot.power_line_id = mi.power_line_id 
    and ot.outage_time > mi.event_timestamp 
) 
, last_power_on AS (
select key, max(event_timestamp) as event_date 
from events_before_outage 
where event_info = 'power on' 
group by 1 
) 
select a.key, a.event_id, a.power_line_id 
from events_before_outage a 
where a.event_timestamp > (select event_date from last_power_on b where a.key = b.key) 
order by 1,2 

Ausgänge:

key | event_id | power_line_id 
-----+----------+--------------- 
    2 |  46 |   247 
    2 |  47 |   247 
    2 |  48 |   247 
    3 |  50 |   247 
    3 |  51 |   247 
    3 |  52 |   247 
    3 |  53 |   247 
0

Hier ist ein vollständig abgebunden basierter Ansatz analytische Funktionen verwenden. Die Idee ist, die "Poweron" s aufzuzählen, indem Sie eine kumulative Zählung von ihnen machen, um Gruppen zu erhalten. Verwenden Sie diese Gruppe dann, um die Zeit von Stromausfällen während der Gruppe zu ermitteln und die Werte zurückzugeben.

select om.* 
from (select om.*, 
      max(om.outagetime) over (partition by poweron_grp, powerlineid) as outagetime, 
      min(event_timestamp) over (partition by powerongrp, powerlineid as minet, 
      max(event_timestamp) over (partition by powerongrp, powerlineid as maxet 
     from (select m.*, o.outagetime, 
        sum(case when m.event_info = 'power on' then 1 else 0 end) over 
         (partition by m.powerlineid order by m.event_timestamp 
         ) as poweron_grp 
      from outages o join 
       meters m 
      on o.powerlineid = m.powerlineid 
      ) om 
    ) om 
where outagetime between minte and maxte and 
     event_timestamp < outagetime; 
0

Mehrere der vorgeschlagenen Antworten verwenden, um eine korrelierte Unterabfrage die volle Zählerinformationstabelle verwenden, obwohl sie brauchen nur die Zeilen für event_info ‚Einschalten‘ =. Korrelierte Unterabfragen werden für jede nachfolgende Zeile ausgewertet, so dass alle diese nicht benötigten Zeilen viele Male ausgewertet und verworfen werden. Wenn es also viele Ereignisse gibt, bei denen sich event_info von "power on" unterscheidet, dann scheint eine zusätzliche Effizienz erreicht zu werden, indem nur die "Power-On" -Ereignisse isoliert werden.

Hier ist eine Möglichkeit, das zu tun. Ich gab den Tabellen die Namen outage_data und meter_data, und in der Tabelle outage_data nannte ich die Spalte "key" outage_ID; Es ist eine wirklich schlechte Idee, Schlüsselwörter als Spaltennamen zu verwenden, und Schlüssel ... ist ... ein Schlüsselwort! Die Unterabfrage (cte) p wird einmal ausgewertet, sie sammelt nur die Ereignisse mit event_info = 'power on' und die korrelierte Unterabfrage ist gegen p, nicht gegen die volle meter_data-Tabelle.

with p as (select power_line, event_time from meter_data where event_info = 'power on') 
select o.outage_ID, m.event_ID, o.power_line 
from  outage_data o join meter_data m on m.power_line = o.power_line 
where m.event_time <= o.outage_time 
    and m.event_time > (select max(p.event_time) from p 
         where p.power_line = o.power_line and p.event_time <= o.outage_time) 
order by o.outage_ID, m.event_ID 
Verwandte Themen