Oracle SQL-连续查找3个月

Oracle SQL-连续查找3个月,sql,oracle,Sql,Oracle,我必须写一个查询,以便按月整理记录。我只需要选择连续3个月。如果连续3个月没有发生,则查询不应拾取值 COLUMN ID DATE 100 01-MAY-2015 100 01-JUN-2015 100 01-JUL-2015 100 01-AUG-2015 111 01-MAY-2015 111 01-JUN-2015

我必须写一个查询,以便按月整理记录。我只需要选择连续3个月。如果连续3个月没有发生,则查询不应拾取值

COLUMN ID   DATE            
100         01-MAY-2015     
100         01-JUN-2015     
100         01-JUL-2015     
100         01-AUG-2015     
111         01-MAY-2015     
111         01-JUN-2015     
111         01-AUG-2015   
111         01-SEP-2015     
122         01-APR-2015     
122         01-MAY-2015 
输出

COLUMN ID   DATE            
100         01-MAY-2015     
100         01-JUN-2015     
100         01-JUL-2015  

任何在Oracle SQL中执行此操作的想法。提前感谢

这个问题很好地说明了Oracle 12.1中引入的MATCH_Recognite子句的威力

with
     inputs ( id, dt ) as (
       select 100, to_date('01-MAY-2015', 'dd-MON-yyyy') from dual union all  
       select 100, to_date('01-JUN-2015', 'dd-MON-yyyy') from dual union all
       select 100, to_date('01-JUL-2015', 'dd-MON-yyyy') from dual union all
       select 100, to_date('01-AUG-2015', 'dd-MON-yyyy') from dual union all
       select 111, to_date('01-MAY-2015', 'dd-MON-yyyy') from dual union all
       select 111, to_date('01-JUN-2015', 'dd-MON-yyyy') from dual union all
       select 111, to_date('01-AUG-2015', 'dd-MON-yyyy') from dual union all
       select 111, to_date('01-SEP-2015', 'dd-MON-yyyy') from dual union all
       select 122, to_date('01-APR-2015', 'dd-MON-yyyy') from dual union all
       select 122, to_date('01-MAY-2015', 'dd-MON-yyyy') from dual
     )
-- End of simulated inputs (for testing only, not part of the SQL query)
select id, dt
from   inputs
match_recognize (
  partition by id
  order by dt
  all rows per match
  pattern ( a b b {-x*-} )
  define b as dt = add_months(prev(dt), 1)
)
;

ID   DT
---  -----------
100  01-MAY-2015
100  01-JUN-2015
100  01-JUL-2015

这个问题是Oracle 12.1中引入的MATCH_RECOGNIZE子句的强大功能的一个很好的例子

with
     inputs ( id, dt ) as (
       select 100, to_date('01-MAY-2015', 'dd-MON-yyyy') from dual union all  
       select 100, to_date('01-JUN-2015', 'dd-MON-yyyy') from dual union all
       select 100, to_date('01-JUL-2015', 'dd-MON-yyyy') from dual union all
       select 100, to_date('01-AUG-2015', 'dd-MON-yyyy') from dual union all
       select 111, to_date('01-MAY-2015', 'dd-MON-yyyy') from dual union all
       select 111, to_date('01-JUN-2015', 'dd-MON-yyyy') from dual union all
       select 111, to_date('01-AUG-2015', 'dd-MON-yyyy') from dual union all
       select 111, to_date('01-SEP-2015', 'dd-MON-yyyy') from dual union all
       select 122, to_date('01-APR-2015', 'dd-MON-yyyy') from dual union all
       select 122, to_date('01-MAY-2015', 'dd-MON-yyyy') from dual
     )
-- End of simulated inputs (for testing only, not part of the SQL query)
select id, dt
from   inputs
match_recognize (
  partition by id
  order by dt
  all rows per match
  pattern ( a b b {-x*-} )
  define b as dt = add_months(prev(dt), 1)
)
;

ID   DT
---  -----------
100  01-MAY-2015
100  01-JUN-2015
100  01-JUL-2015

仅使用分析函数的解决方案(应适用于Oracle 9及更高版本)

注意:我已经为Oracle 12.1及以上版本发布了另一个答案。这是一个完全不同的方法,因此它确实是一个不同的答案(即使是由同一个人发布的)

为简单起见,此查询仅返回ID和至少连续三个月的第一个月。与MATCH_Recognite解决方案一样,在该解决方案中,我们也只查找连续三个月的第一次出现。(对于同一个ID,可能有连续五个月,或者在两个不同的地方有连续三个月-我们只识别连续三个月中的第一次出现。)如果所有三行-所有三个月-都需要,这很容易适应

with
     inputs ( id, dt ) as (
       select 100, to_date('01-MAY-2015', 'dd-MON-yyyy') from dual union all  
       select 100, to_date('01-JUN-2015', 'dd-MON-yyyy') from dual union all
       select 100, to_date('01-JUL-2015', 'dd-MON-yyyy') from dual union all
       select 100, to_date('01-AUG-2015', 'dd-MON-yyyy') from dual union all
       select 111, to_date('01-MAY-2015', 'dd-MON-yyyy') from dual union all
       select 111, to_date('01-JUN-2015', 'dd-MON-yyyy') from dual union all
       select 111, to_date('01-AUG-2015', 'dd-MON-yyyy') from dual union all
       select 111, to_date('01-SEP-2015', 'dd-MON-yyyy') from dual union all
       select 122, to_date('01-APR-2015', 'dd-MON-yyyy') from dual union all
       select 122, to_date('01-MAY-2015', 'dd-MON-yyyy') from dual
     )
-- End of simulated inputs (for testing only, not part of the SQL query)
select id, min(dt) as dt
from (
       select id, dt, 
              case when lead(dt, 1) over (partition by id order by dt) = add_months(dt, 1)
                    and lead(dt, 2) over (partition by id order by dt) = add_months(dt, 2)
                   then 1 
              end as flag
       from   inputs
     )
where    flag = 1
group by id
;

 ID  DT        
---  -----------
100  01-MAY-2015

仅使用分析函数的解决方案(应适用于Oracle 9及更高版本)

注意:我已经为Oracle 12.1及以上版本发布了另一个答案。这是一个完全不同的方法,因此它确实是一个不同的答案(即使是由同一个人发布的)

为简单起见,此查询仅返回ID和至少连续三个月的第一个月。与MATCH_Recognite解决方案一样,在该解决方案中,我们也只查找连续三个月的第一次出现。(对于同一个ID,可能有连续五个月,或者在两个不同的地方有连续三个月-我们只识别连续三个月中的第一次出现。)如果所有三行-所有三个月-都需要,这很容易适应

with
     inputs ( id, dt ) as (
       select 100, to_date('01-MAY-2015', 'dd-MON-yyyy') from dual union all  
       select 100, to_date('01-JUN-2015', 'dd-MON-yyyy') from dual union all
       select 100, to_date('01-JUL-2015', 'dd-MON-yyyy') from dual union all
       select 100, to_date('01-AUG-2015', 'dd-MON-yyyy') from dual union all
       select 111, to_date('01-MAY-2015', 'dd-MON-yyyy') from dual union all
       select 111, to_date('01-JUN-2015', 'dd-MON-yyyy') from dual union all
       select 111, to_date('01-AUG-2015', 'dd-MON-yyyy') from dual union all
       select 111, to_date('01-SEP-2015', 'dd-MON-yyyy') from dual union all
       select 122, to_date('01-APR-2015', 'dd-MON-yyyy') from dual union all
       select 122, to_date('01-MAY-2015', 'dd-MON-yyyy') from dual
     )
-- End of simulated inputs (for testing only, not part of the SQL query)
select id, min(dt) as dt
from (
       select id, dt, 
              case when lead(dt, 1) over (partition by id order by dt) = add_months(dt, 1)
                    and lead(dt, 2) over (partition by id order by dt) = add_months(dt, 2)
                   then 1 
              end as flag
       from   inputs
     )
where    flag = 1
group by id
;

 ID  DT        
---  -----------
100  01-MAY-2015

什么版本的Oracle?根据版本的不同,可以使用不同的方法。Mathguy,我使用的是Oracle版本11g Oracle的哪个版本?根据版本的不同,可以使用不同的方法。Mathguy,我使用的是Oracle版本11gMathguy,如果我们连续需要4条或更多记录,该怎么办???这在Oracle 11g上有效吗?难以置信!在任何情况下:模式是
abb{-x*}
-这意味着,在每个分区(按id分组)中,按日期排序后,查找第一行(
a
)不受限制的任何行序列;第二行和第三行均为
b类
,受
定义
条件限制;以及输出中未显示的任意数量的非限制行(class
x
)(
{-…-}
表示法)。因此,如果您需要,比如说,连续四个月,将模式更改为
abb{-x*-}
,连续五个月更改为
abb{-x*-}
,等等。Mathguy,如果我们需要连续四行或更多记录,该如何处理???这在Oracle 11g上有效吗?难以置信!在任何情况下:模式是
abb{-x*}
-这意味着,在每个分区(按id分组)中,按日期排序后,查找第一行(
a
)不受限制的任何行序列;第二行和第三行均为
b类
,受
定义
条件限制;以及输出中未显示的任意数量的非限制行(class
x
)(
{-…-}
表示法)。因此,如果您需要,比如说,连续四个月,将模式更改为
abb{-x*-}
,连续五个月更改为
abb{-x*-}
,等等。