Reputation: 27
I have to write a query to find 3 or more consecutive occurrence of a value (Refer Column Flag) and it must happen on consecutive dates.The query should not pick values if the occurrence doesn't happen on consecutive dates For e.g
COLUMN ID DATE FLAG
100 10-JUL-2015 Y
100 11-JUL-2015 Y
100 12-JUL-2015 Y
100 13-JUL-2015 N
100 14-JUL-2015 Y
100 15-JUL-2015 Y
100 16-JUL-2015 N
100 17-JUL-2015 Y
100 18-JUL-2015 Y
100 19-JUL-2015 Y
100 20-JUL-2015 Y
100 21-JUL-2015 Y
OUTPUT
COLUMN ID DATE FLAG
100 10-JUL-2015 Y
100 11-JUL-2015 Y
100 12-JUL-2015 Y
100 17-JUL-2015 Y
100 18-JUL-2015 Y
100 19-JUL-2015 Y
100 20-JUL-2015 Y
100 21-JUL-2015 Y
Any Idea to accomplish this in Oracle SQL. I am trying to use analytic functions like LAG and LEAD but unable to accomplish this.
Upvotes: 1
Views: 5716
Reputation: 49260
You can try this. This makes use of recursive common table expressions and lead
analytical function.
with x as
(select id, mydate, flag from table1 where flag = 'Y')
, y as(select id, mydate, lead(mydate) over(order by mydate) as nxt,flag from x)
, z as (select id, mydate, nxt, lead(nxt) over(order by nxt) as nxt_1,flag from y)
select distinct t.id, t.mydate,t.flag from z
join x t on z.id = t.id
and (t.mydate = z.mydate or t.mydate = z.nxt or t.mydate = z.nxt_1)
where z.nxt-z.mydate = 1 and z.nxt_1-z.nxt =1
order by t.mydate
SQLfiddle with test data : http://sqlfiddle.com/#!4/9bbed/1
Upvotes: 0
Reputation: 1269513
You can do this with a very handy trick. The groups of consecutive values can be calculated using a difference of row_number()
s. Then, you need to get the count for each group and select the ones that match your condition:
select t.*
from (select t.*, count(*) over (partition by id, flag, grp) as cnt
from (select t.*,
(row_number() over (partition by id order by date) -
row_number() over (partition by id, flag order by date)
) as grp
from table t
) t
) t
where cnt >= 3;
Strictly speaking, you do not need the difference of row_numbers()
. Assuming your dates have no time components, the following will also suffice:
select t.*
from (select t.*, count(*) over (partition by id, flag, grp) as cnt
from (select t.*,
(date -
row_number() over (partition by id, flag order by date)
) as grp
from table t
) t
) t
where cnt >= 3;
Upvotes: 3