Oracle SQL - 在行中查找3个连续的MONTH

时间:2017-09-28 02:46:24

标签: sql oracle

我必须编写一个查询来按MONTH整理记录顺序。我只需要连续选择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中执行此操作。提前致谢

2 个答案:

答案 0 :(得分:2)

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

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

为简单起见,此查询仅返回至少连续三个月的ID和第一个月。与MATCH_RECOGNIZE解决方案一样,在此解决方案中,我们也只查找连续三个月的第一次出现。 (对于相同的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

答案 1 :(得分:1)

这个问题很好地说明了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