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

Spojení po sobě jdoucích intervalů platnosti data

To je problém mezer a ostrovů. Existují různé způsoby, jak k tomu přistupovat; toto používá lead a lag analytické funkce:

select distinct product,
  case when start_date is null then lag(start_date)
    over (partition by product order by rn) else start_date end as start_date,
  case when end_date is null then lead(end_date)
    over (partition by product order by rn) else end_date end as end_date
from (
  select product, start_date, end_date, rn
  from (
    select t.product,
      case when lag(end_date)
          over (partition by product order by start_date) is null
        or lag(end_date)
          over (partition by product order by start_date) != start_date - 1
        then start_date end as start_date,
      case when lead(start_date)
          over (partition by product order by start_date) is null
        or lead(start_date)
          over (partition by product order by start_date) != end_date + 1
        then end_date end as end_date,
      row_number() over (partition by product order by start_date) as rn
    from t
  )
  where start_date is not null or end_date is not null
)
order by start_date, product;

PRODUCT START_DATE END_DATE
------- ---------- ---------
A       01-JUL-13  30-SEP-13 
B       01-OCT-13  30-NOV-13 
A       01-DEC-13  31-MAR-14 

SQL Fiddle

Nejvnitřnější dotaz se dívá na předchozí a následující záznamy pro produkt a zachovává počáteční a/nebo koncový čas pouze v případě, že záznamy nejsou souvislé:

select t.product,
  case when lag(end_date)
      over (partition by product order by start_date) is null
    or lag(end_date)
      over (partition by product order by start_date) != start_date - 1
    then start_date end as start_date,
  case when lead(start_date)
      over (partition by product order by start_date) is null
    or lead(start_date)
      over (partition by product order by start_date) != end_date + 1
    then end_date end as end_date
from t;

PRODUCT START_DATE END_DATE
------- ---------- ---------
A       01-JUL-13            
A                            
A                  30-SEP-13 
A       01-DEC-13            
A                            
A                            
A                  31-MAR-14 
B       01-OCT-13            
B                  30-NOV-13 

Další úroveň výběru odstraní ty, které jsou uprostřed období, kde byla obě data vymazána vnitřním dotazem, což dává:

PRODUCT START_DATE END_DATE
------- ---------- ---------
A       01-JUL-13            
A                  30-SEP-13 
A       01-DEC-13            
A                  31-MAR-14 
B       01-OCT-13            
B                  30-NOV-13 

Vnější dotaz pak tyto sousední páry sbalí; Použil jsem snadný způsob vytváření duplikátů a jejich odstranění pomocí distinct , ale můžete to udělat i jinými způsoby, jako je vložení obou hodnot do jednoho z párů řádků a ponechání obou hodnot ve druhém null, a pak odstranění těch s další vrstvou výběru, ale myslím, že rozdíl je zde v pořádku.

Pokud váš případ použití v reálném světě obsahuje časy, ne jen data, budete muset upravit srovnání ve vnitřním dotazu; spíše než +/- 1, možná interval 1 sekundy nebo 1/86400, chcete-li, ale záleží na přesnosti vašich hodnot.



  1. Tipy pro monitorování replikace MariaDB pomocí ClusterControl

  2. Jedinečné omezení na jeden sloupec s vyloučením řádku se stejnými hodnotami v jiném

  3. Neplatný výraz PathExpression. Musí to být StateFieldPathExpression

  4. Vložit hodnoty z tabulky A do tabulky A