我必须编写一个查询来按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中执行此操作。提前致谢
答案 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