根据日期范围查找至少2个连续项

问题描述

有很多类似问题的解决方案,但仅基于一个日期列。

我想知道也许可以解决这个问题的更好的解决方案,我附上了我的解决方案,但是如果您知道更好的解决方案,请发贴。

这是带有订单的表,订单的开始和结束日期为2个项目。 我想根据日期和项目打印至少2个连续的行。

   ITEM,START,END
1. A,01.01.2020,31.01.2020
2. A,01.02.2020,31.03.2020
3. B,30.04.2020
4. A,01.05.2020,30.06.2020
5. B,01.06.2020,31.07.2020
6. B,01.09.2020,30.09.2020
7. A,01.08.2020,31.10.2020
8. B,01.10.2020,31.10.2020
9. B,01.11.2020,31.12.2020

对于项目A,输出应为第1行和第2行,对于项目B,输出应为第6、8和9行


这是我的助手

with pool as (
                    select ITEM,START_DATE,END_DATE,nvl(lag(end_date,1) over (partition by item order by end_date),START_DATE-1) prev_End_Date                    
                    from orders  ),pool2 as     (
                    select item,sum(case when PREV_END_DATE+1 = START_DATE then 0 else 1 end ) over (partition by item order by START_DATE) grp
                              from pool )
select item,start_date,end_date from (
select 
          ITEM,grp,count(grp) over (partition by item,grp ) cnt
 from pool2)
 where cnt>=2
 ;

解决方法

嗯。 。 。使用lag()lead()查看下一个/上一个值,并检查它们是否匹配:

select o.*
from (select o.*,lag(end) over (partition by product order by start) as prev_end,lead(start) over (partition by product order by start) as next_start
      from orders o
     ) o
where start = prev_end + interval '1' day or
      end = next_start - interval '1' day;
,

-创建表并插入测试行

Create table order_overlap (id number,item varchar2(1),start_date date,end_date date );
 

insert into order_overlap(id,start_date,end_date,item) values( 1,to_date('01.01.2020','dd.mm.yyyy'),to_date( '31.01.2020','A');
insert into order_overlap(id,item) values( 2,to_date('01.02.2020',to_date( '31.03.2020',item) values( 3,to_date( '30.04.2020','B');
insert into order_overlap(id,item) values( 4,to_date('01.05.2020',to_date( '30.06.2020',item) values( 5,to_date('01.06.2020',to_date( '31.07.2020',item) values( 6,to_date('01.09.2020',to_date( '30.09.2020',item) values( 7,to_date('01.08.2020',to_date( '31.10.2020',item) values( 8,to_date('01.10.2020',to_date('01.11.2020',to_date( '31.12.2020','B');

-我确实有些不同,但也许您喜欢它。 -我将好斗的行合并为一-如果您有项目 A 01.01.2020-31.01.2020 A 01.02.2020-28.02.2020

你得到一个秘诀 A 01.01.2020-28.02.2020

 select item,min(start_date) start_date,max(end_date) end_date,count(*)  
 from (  
   select item,case when lead(start_date) over(partition by item order by start_date) = end_date + 1   
      OR lag(end_date) over(partition by item order by end_date) + 1 = start_date   
      then 0  
      else rownum  
     end continuity  
   from order_overlap ) 
 group by item,continuity
 order by item,start_date;  
,

您可以简单地使用MATCH_RECOGNIZE进行逐行比较,并只返回与模式匹配的行组:

SELECT *
FROM   table_name
MATCH_RECOGNIZE (
  PARTITION BY item
  ORDER BY start_date,end_date
  ALL ROWS PER MATCH
  PATTERN ( FIRST_ROW NEXT_ROWS+ )
  DEFINE
    NEXT_ROWS AS (
      NEXT_ROWS.START_DATE = PREV( END_DATE ) + INTERVAL '1' DAY
    )
)

因此,对于您的示例数据:

CREATE TABLE table_name ( ITEM,START_DATE,END_DATE ) AS
SELECT 'A',DATE '2020-01-01',DATE '2020-01-31' FROM DUAL UNION ALL
SELECT 'A',DATE '2020-02-01',DATE '2020-03-31' FROM DUAL UNION ALL
SELECT 'B',DATE '2020-04-30' FROM DUAL UNION ALL
SELECT 'A',DATE '2020-05-01',DATE '2020-06-30' FROM DUAL UNION ALL
SELECT 'B',DATE '2020-06-01',DATE '2020-07-31' FROM DUAL UNION ALL
SELECT 'B',DATE '2020-09-01',DATE '2020-09-30' FROM DUAL UNION ALL
SELECT 'A',DATE '2020-08-01',DATE '2020-10-31' FROM DUAL UNION ALL
SELECT 'B',DATE '2020-10-01',DATE '2020-11-01',DATE '2020-12-31' FROM DUAL;

这将输出:

ITEM | START_DATE | END_DATE  
:--- | :--------- | :---------
A    | 2020-01-01 | 2020-01-31
A    | 2020-02-01 | 2020-03-31
B    | 2020-09-01 | 2020-09-30
B    | 2020-10-01 | 2020-10-31
B    | 2020-11-01 | 2020-12-31

db 提琴here