Oracle
 sql >> Database >  >> RDS >> Oracle

Come faccio a catturare l'evento "successivo" quando l'offset è variabile per gli elementi che possono essere elaborati ripetutamente?

Questo è un problema di lacune e isole, ma le isole sono definite da un REQ transazione lo rendono un po' più complicato di altri.

Potresti usare le funzioni nidificate di anticipo e ritardo e alcune manipolazioni per ottenere ciò di cui hai bisogno:

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;

Con record aggiuntivi per un secondo ciclo per gli articoli 1 e 2 che potrebbero dare:

      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 Fiddle mostrando tutti i passaggi intermedi.

Non è così spaventoso come potrebbe sembrare a prima vista. La query più interna prende i dati grezzi e aggiunge una colonna aggiuntiva per le transazioni lead e lag. Prendendo solo il primo set di record dell'elemento 1 che sarebbe:

      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      

Avviso REQ-E spuntando come l'ultimo lead_tran ? Questa è la prima transaction per il secondo ciclo di record per questo elemento e sarà utile in seguito. Il livello successivo di query utilizza quei valori di lead e lag e tratta REQ valori come indicatori di inizio e fine e utilizza tali informazioni per annullare tutto tranne il primo e l'ultimo record per ogni ciclo.

      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     

Il livello successivo di query rimuove tutte le righe che non rappresentano l'inizio o la fine (o entrambi - vedi REQ-F nel violino) perché non ci interessano:

      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     

Ora abbiamo coppie di righe per ogni ciclo (o una singola riga per REQ-F ). Il livello finale utilizza di nuovo lead e lag per riempire gli spazi vuoti; se il start_tran è null, quindi questa è una riga finale e dovremmo usare i dati iniziali della riga precedente; se end_tran è null, quindi questa è una riga iniziale e dovremmo usare i dati finali della riga successiva.

  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 

Ciò rende entrambe le righe uguali, quindi distinct rimuove i duplicati.