Đây là một vấn đề về khoảng cách và các đảo. Có nhiều cách khác nhau để tiếp cận nó; cái này sử dụng lead
và lag
chức năng phân tích:
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
Truy vấn trong cùng xem xét các bản ghi trước và sau cho sản phẩm và chỉ giữ lại thời gian bắt đầu và / hoặc kết thúc nếu các bản ghi không liền nhau:
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
Cấp độ lựa chọn tiếp theo sẽ loại bỏ những ngày ở giữa khoảng thời gian, trong đó cả hai ngày đều bị truy vấn bên trong để trống, điều này mang lại:
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
Sau đó, truy vấn bên ngoài sẽ thu gọn các cặp liền kề đó; Tôi đã sử dụng cách dễ dàng để tạo các bản sao và sau đó loại bỏ chúng bằng distinct
, nhưng bạn có thể làm theo những cách khác, chẳng hạn như đặt cả hai giá trị vào một trong các cặp hàng và để cả hai giá trị ở giá trị khác rỗng, sau đó loại bỏ những giá trị đó bằng một lớp chọn khác, nhưng tôi nghĩ việc phân biệt là OK ở đây.
Nếu trường hợp sử dụng trong thế giới thực của bạn có thời gian, không chỉ ngày, thì bạn sẽ cần điều chỉnh so sánh trong truy vấn bên trong; thay vì +/- 1, khoảng thời gian có thể là 1 giây hoặc 1/86400 nếu bạn thích, nhưng phụ thuộc vào độ chính xác của các giá trị của bạn.