sql >> Database >  >> RDS >> Oracle

Hoe pak ik de "volgende" gebeurtenis wanneer de offset variabel is voor items die herhaaldelijk kunnen worden verwerkt?

Dit is een gaps-and-islands-probleem, maar de eilanden worden gedefinieerd door een REQ transactie maken het een beetje ingewikkelder dan sommige.

Je zou geneste lead- en lag-functies en wat manipulatie kunnen gebruiken om te krijgen wat je nodig hebt:

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;

Met aanvullende records voor een tweede cyclus voor items 1 en 2 die het volgende kunnen opleveren:

      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 toont alle tussenliggende stappen.

Het is niet zo eng als het op het eerste gezicht lijkt. De binnenste query neemt de onbewerkte gegevens en voegt een extra kolom toe voor de lead- en lag-transacties. Alleen de eerste set item-1-records nemen, zou zijn:

      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      

Opmerking REQ-E opduiken als de laatste lead_tran ? Dat is de eerste transaction voor de tweede cyclus van records voor dit item, en zal later nuttig zijn. Het volgende queryniveau gebruikt die lead- en lag-waarden en behandelt REQ waarden als begin- en eindmarkeringen en gebruikt die informatie om alles op nul te zetten, behalve het eerste en laatste record voor elke cyclus.

      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     

Het volgende zoekniveau verwijdert alle rijen die niet het begin of einde vertegenwoordigen (of beide - zie REQ-F in de viool) omdat we er niet in geïnteresseerd zijn:

      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     

We hebben nu rijenparen voor elke cyclus (of een enkele rij voor REQ-F ). Het laatste niveau gebruikt opnieuw lood en lag om de lege plekken in te vullen; als de start_tran is null, dan is dit een eindrij en moeten we de startgegevens van de vorige rij gebruiken; if end_tran is null, dan is dit een startrij en moeten we de eindgegevens van de volgende rij gebruiken.

  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 

Dat maakt beide rijen hetzelfde, dus de distinct verwijdert de duplicaten.



  1. org.hibernate.MappingException:geen dialecttoewijzing voor JDBC-type:1111

  2. MySQL Stored Procedure Error Onverwacht teken:

  3. Gebruik FILEGROUP_ID() om de ID van een bestandsgroep in SQL Server te retourneren

  4. Is NOLOCK de standaard voor SELECT-instructies in SQL Server 2005?