Find broken sequence with match_recognize with Oracle 12C
I want to detect gaps in my CDR_ID sequence for each number because I am using the match_recognize analytic function.
code:
SQL> select distinct number,
cdr_id,
status_sequence
from TMP_CDR_GAPS match_recognize (
partition by number
order by cdr_id
measures match_number() status_sequence
all rows per match
after match skip past last row
pattern (section_start in_seq_value*)
define in_seq_value as (cdr_id = prev(cdr_id))
)
As a result, I get:
NUMBER CDR_ID STATUS_SEQUENCE
003301011849 536 1
003301011849 537 2
003301011849 538 3
003301011849 539 4
003301011849 540 5
003301011849 541 6
003301011849 542 7
003301011849 544 8 <-- !!!
003301011849 545 9
003301011849 546 10
003301011849 547 11
003301011849 548 12
You will notice that CDR_ID 543 is missing , which is exactly what I want to detect, so I expect STATUS_SEQUENCE to restart to 1 for the next CDR_ID (CDR_ID 544 in this case).
Can someone help me understand what is wrong with the match_recognize syntax?
Thanks David
source to share
With multiple analysts stacking on top of each other ...
with detect_first_in_seq$ as (
select X.*,
case when lnnvl(lag(X.cdr_id) over (partition by num order by cdr_id) = X.cdr_id-1) then X.cdr_id end as is_first_cdr_id_in_seq
from tmp_cdr_gaps X
),
copy_first_in_seq$ as (
select X.*,
last_value(is_first_cdr_id_in_seq ignore nulls) over (partition by num order by cdr_id) as first_cdr_id_in_seq
from detect_first_in_seq$ X
)
select
X.*,
row_number() over (partition by num, first_cdr_id_in_seq order by cdr_id) as status_sequence
from copy_first_in_seq$ X
;
With a slightly modified request of yours and one more analytical ...
select num, cdr_id,
row_number() over (partition by num, sequence_group order by cdr_id) as status_sequence
from tmp_cdr_gaps
match_recognize (
partition by num
order by cdr_id
measures match_number() sequence_group
all rows per match
after match skip past last row
pattern (section_start in_seq_value*)
define in_seq_value as (cdr_id = prev(cdr_id)+1)
);
And finally, only with match_recognize
...
select *
from tmp_cdr_gaps
match_recognize (
partition by num
order by cdr_id
measures count(1) as status_sequence
all rows per match
after match skip past last row
pattern (sequence_group in_sequence*)
define in_sequence as (cdr_id = prev(cdr_id)+1)
);
This works because, as I discovered in the Oracle doc , aggregate functions in match_recognize()
have modus functions by default doing aggregates.
Thanks for getting me a little closer to mastering this great addition to SQL. :-)
Regarding yours Can someone help me understand what is wrong with the match_recognize syntax? ...
There are several errors:
- Yours
in_seq_value
, defined ascdr_id = prev(cdr_id)
, doesn't make sense. With this definition, you are saying that you want to identify sequences of the same valuescdr_id
, whereas you really want to identify sequences of valuescdr_id
that increase by 1. - Your
match_number() status_sequence
numbers are sequentially each found pattern. Forcdr_id = prev(cdr_id)
such a template, it will correspond to 12 one-line "subgroups", each of which will be numbered sequentially. Forcdr_id = prev(cdr_id)+1
that will be1
for linescdr_id
from536
to542
and2
for linescdr_id
from544
to548
.
source to share