Oracle
 sql >> Datenbank >  >> RDS >> Oracle

Wie erhalte ich das „nächste“ Ereignis, wenn der Offset für Elemente, die wiederholt verarbeitet werden können, variabel ist?

Dies ist ein Lücken-und-Inseln-Problem, aber die Inseln werden durch ein REQ definiert Transaktion machen es etwas komplizierter als manche.

Sie könnten verschachtelte Lead- und Lag-Funktionen und einige Manipulationen verwenden, um das zu bekommen, was Sie brauchen:

select distinct item,
  coalesce(start_tran,
    lag(start_tran) over (partition by item order by timestamp)) as start_tran,
  coalesce(end_tran,
    lead(end_tran) over (partition by item order by timestamp)) as end_tran,
  coalesce(end_time, 
    lead(end_time) over (partition by item order by timestamp))
    - coalesce(start_time,
        lag(start_time) over (partition by item order by timestamp)) as time
from (
  select item, timestamp, start_tran, start_time, end_tran, end_time
  from (
    select item,
      timestamp,
      case when lag_tran is null or transaction like 'REQ%'
        then transaction end as start_tran,
      case when lag_tran is null or transaction like 'REQ%'
        then timestamp end as start_time,
      case when lead_tran is null or lead_tran like 'REQ%'
        then transaction end as end_tran,
      case when lead_tran is null or lead_tran like 'REQ%'
        then timestamp end as end_time
    from (
      select item, transaction, timestamp,
        lag(transaction)
          over (partition by item order by timestamp) as lag_tran,
        lead(transaction)
          over (partition by item order by timestamp) as lead_tran
      from transactions
    )
  )
  where start_tran is not null or end_tran is not null
)
order by item, start_tran;

Mit zusätzlichen Datensätzen für einen zweiten Zyklus für die Elemente 1 und 2, die Folgendes ergeben könnten:

      ITEM START_TRAN END_TRAN   TIME      
---------- ---------- ---------- -----------
         1 REQ-A      PICKUP     0 1:53:30.0 
         1 REQ-E      PICKUP     0 1:23:30.0 
         2 REQ-B      MAIL       0 0:24:13.0 
         2 REQ-F      REQ-F      0 0:0:0.0   
         3 REQ-C      PICKUP     0 1:46:30.0 
         4 REQ-D      PULL       0 0:23:59.0 
         5 REQ-A      PICKUP     0 1:43:59.0 

SQL-Geige zeigt alle Zwischenschritte.

Es ist nicht ganz so gruselig, wie es auf den ersten Blick aussehen mag. Die innerste Abfrage nimmt die Rohdaten und fügt eine zusätzliche Spalte für die Lead- und Lag-Transaktionen hinzu. Nimmt man nur den ersten Satz von item-1 Datensätzen, wäre das:

      ITEM TRANSACTION TIMESTAMP                LAG_TRAN   LEAD_TRAN
---------- ----------- ------------------------ ---------- ----------
         1 REQ-A       2014-07-31T09:51:32Z                PULL       
         1 PULL        2014-07-31T10:22:21Z     REQ-A      TRANSFER   
         1 TRANSFER    2014-07-31T10:22:23Z     PULL       ARRIVE     
         1 ARRIVE      2014-07-31T11:45:01Z     TRANSFER   PICKUP     
         1 PICKUP      2014-07-31T11:45:02Z     ARRIVE     REQ-E      

Beachten Sie REQ-E erscheint als letzter lead_tran ? Das ist die erste transaction für den zweiten Datensatzzyklus für dieses Element und wird später nützlich sein. Die nächste Abfrageebene verwendet diese Lead- und Lag-Werte und behandelt REQ Werte als Start- und Endmarkierungen und verwendet diese Informationen, um alles außer dem ersten und letzten Datensatz für jeden Zyklus auf Null zu setzen.

      ITEM TIMESTAMP                START_TRAN START_TIME               END_TRAN   END_TIME               
---------- ------------------------ ---------- ------------------------ ---------- ------------------------
         1 2014-07-31T09:51:32Z     REQ-A      2014-07-31T09:51:32Z                                         
         1 2014-07-31T10:22:21Z                                                                             
         1 2014-07-31T10:22:23Z                                                                             
         1 2014-07-31T11:45:01Z                                                                             
         1 2014-07-31T11:45:02Z                                         PICKUP     2014-07-31T11:45:02Z     

Die nächste Abfrageebene entfernt alle Zeilen, die nicht den Anfang oder das Ende darstellen (oder beides - siehe REQ-F in the Fiddle), da sie uns nicht interessieren:

      ITEM TIMESTAMP                START_TRAN START_TIME               END_TRAN   END_TIME               
---------- ------------------------ ---------- ------------------------ ---------- ------------------------
         1 2014-07-31T09:51:32Z     REQ-A      2014-07-31T09:51:32Z                                         
         1 2014-07-31T11:45:02Z                                         PICKUP     2014-07-31T11:45:02Z     

Wir haben jetzt Zeilenpaare für jeden Zyklus (oder eine einzelne Zeile für REQ-F ). Die letzte Ebene verwendet wieder Lead und Lag, um die Lücken zu füllen; wenn der start_tran null ist, dann ist dies eine Endzeile und wir sollten die Startdaten der vorherigen Zeile verwenden; wenn end_tran null ist, dann ist dies eine Startzeile und wir sollten die Enddaten der nächsten Zeile verwenden.

  ITEM START_TRAN START_TIME               END_TRAN   END_TIME                 TIME      
     1 REQ-A      2014-07-31T09:51:32Z     PICKUP     2014-07-31T11:45:02Z     0 1:53:30.0 
     1 REQ-A      2014-07-31T09:51:32Z     PICKUP     2014-07-31T11:45:02Z     0 1:53:30.0 

Das macht beide Zeilen gleich, also den distinct entfernt die Duplikate.