sql >> Databáze >  >> RDS >> Oracle

Jak získám událost „další“, když je posun proměnný u položek, které lze opakovaně zpracovávat?

Toto je problém mezer a ostrovů, ale ostrovy jsou definovány pomocí REQ transakce, aby to bylo trochu komplikovanější než jiné.

K získání toho, co potřebujete, můžete použít vnořené funkce lead a lag a nějakou manipulaci:

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;

S dalšími záznamy pro druhý cyklus pro položky 1 a 2, které by mohly poskytnout:

      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 zobrazující všechny mezikroky.

Není to tak děsivé, jak by se na první pohled mohlo zdát. Nejvnitřnější dotaz přebírá nezpracovaná data a přidává další sloupec pro transakce potenciálního zákazníka a zpoždění. Vezmeme-li pouze první sadu záznamů item-1, která by byla:

      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      

Všimněte si REQ-E vyskakující jako poslední lead_tran ? To je první transaction pro druhý cyklus záznamů pro tuto položku a bude užitečný později. Další úroveň dotazu používá tyto hodnoty předstihu a zpoždění a zpracovává REQ hodnoty jako počáteční a koncové značky a používá tyto informace k vynulování všeho kromě prvního a posledního záznamu pro každý cyklus.

      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     

Další úroveň dotazu odstraní všechny řádky, které nepředstavují začátek nebo konec (nebo obojí – viz REQ-F v houslích), protože nás nezajímají:

      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     

Nyní máme páry řádků pro každý cyklus (nebo jeden řádek pro REQ-F ). Konečná úroveň znovu používá olovo a zpoždění k vyplnění prázdných míst; pokud start_tran je null, pak se jedná o koncový řádek a měli bychom použít počáteční data předchozího řádku; pokud end_tran je null, pak se jedná o počáteční řádek a měli bychom použít koncová data dalšího řádku.

  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 

Díky tomu jsou oba řádky stejné, takže se distinct odstraní duplikáty.



  1. Jak mohu použít alias v klauzuli where?

  2. SQL vrátí 100 náhodných řádků pro každý věk

  3. Funkce PostgreSQL pro iteraci/působení na mnoha řádcích se stavem

  4. Problém s formátem čísel v Oracle