Oracle
 sql >> база данни >  >> RDS >> Oracle

Обединяване на последователни интервали на валидност на датата

Това е проблем с пропуски и острови. Има различни начини за подход; това използва lead и lag аналитични функции:

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

Най-вътрешната заявка разглежда предходните и следващите записи за продукта и запазва само началния и/или крайния час, ако записите не са последователни:

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 

Следващото ниво на избор премахва онези, които са в средата на периода, където и двете дати са празни от вътрешната заявка, което дава:

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 

След това външната заявка свива тези съседни двойки; Използвах лесния път за създаване на дубликати и след това премахването им с distinct , но можете да го направите по други начини, като поставяне на двете стойности в една от двойките редове и оставяне на двете стойности в другата нула и след това елиминиране на тези с друг слой за избиране, но мисля, че distinct е ОК тук.

Ако вашият случай на използване в реалния свят има времена, а не само дати, тогава ще трябва да коригирате сравнението във вътрешната заявка; вместо +/- 1, може би интервал от 1 секунда или 1/86400, ако предпочитате, но зависи от точността на вашите стойности.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Намерих неизвестен символ на релационна диаграма в Oracle SQL Developer

  2. Как да добавя ненулева колона и ограничение за проверка в един ред в Oracle 11g?

  3. Изтрийте дублиращи се записи с помощта на rownum в sql

  4. SQL- Разлика между TIMESTAMP, DATE И TIMESTAMP С ЧАСОВА ЗОНА?

  5. Липсва дясна скоба при SQL команда за създаване на таблица