Oracle
 sql >> Baza danych >  >> RDS >> Oracle

Łączenie kolejnych przedziałów ważności dat

To jest problem luk i wysp. Można do tego podejść na różne sposoby; używa lead i lag funkcje analityczne:

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 

Skrzypce SQL

Najbardziej wewnętrzne zapytanie analizuje poprzedni i następny rekord produktu i zachowuje czas rozpoczęcia i/lub zakończenia tylko wtedy, gdy rekordy nie są ciągłe:

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 

Następny poziom wyboru usuwa te, które są w połowie okresu, w których obie daty zostały wymazane przez wewnętrzne zapytanie, co daje:

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 

Zewnętrzne zapytanie następnie zwija te sąsiednie pary; Skorzystałem z łatwej drogi tworzenia duplikatów, a następnie eliminowania ich za pomocą distinct , ale możesz to zrobić na inne sposoby, na przykład wstawiając obie wartości do jednej z par wierszy i pozostawiając obie wartości w drugiej wartości null, a następnie eliminując te z inną warstwą zaznaczania, ale myślę, że odróżnienie jest tutaj OK.

Jeśli Twój rzeczywisty przypadek użycia ma godziny, a nie tylko daty, musisz dostosować porównanie w zapytaniu wewnętrznym; zamiast +/- 1, być może w odstępie 1 sekundy lub 1/86400, jeśli wolisz, ale zależy to od precyzji Twoich wartości.



  1. Database
  2.   
  3. Mysql
  4.   
  5. Oracle
  6.   
  7. Sqlserver
  8.   
  9. PostgreSQL
  10.   
  11. Access
  12.   
  13. SQLite
  14.   
  15. MariaDB
  1. Niespójna transpozycja

  2. Jak mogę uzyskać różnicę w godzinach między dwiema datami?

  3. c# wybierz zapytanie do bazy danych Oracle rzuca Niestandardowe mapowanie typu dla ... nie jest określone lub jest nieprawidłowe

  4. Problem z porównaniem ciągów Oracle PL/SQL

  5. SELECT DISTINCT CLOB_COLUMN Z TABELI;