当前位置:网站首页>92 match for several_ Recognize SQL write example

92 match for several_ Recognize SQL write example

2022-06-22 21:23:00 Tiger Liu

stay SQL Support row matching pattern in match_recognize How to write it , yes oracle from 12c Starting with , It's very powerful , The grammar seems a little complicated , With ordinary SQL Very different .

oracle When introducing this new method , Take one example to get a stock V Type diagram (2 A peak and a valley ) Example ( There are many introductions on the Internet , Are used in this example ), But except for this example , There are few other application cases , Here is a place to throw a brick at , Introduce some examples of match_recognize Solutions to problems , For reference only .

Example (1) : Remove the continuous repetition state , Keep only the first , Here's the picture , The red lines are the records that need to be removed

This problem is also relatively simple if it is implemented with an analysis function , The following is to use match_recognize Method of implementation :

with d (type,dt,status)as

( select 'X' ,date '2021-7-1','1' from dual

union all select 'X' ,date '2021-7-2','1' from dual

union all select 'X' ,date '2021-7-3','0' from dual

union all select 'X' ,date '2021-7-4','0' from dual

union all select 'X' ,date '2021-7-5','1' from dual

union all select 'X' ,date '2021-7-6','0' from dual

union all select 'X' ,date '2021-7-7','0' from dual

union all select 'X' ,date '2021-7-8','0' from dual

union all select 'X' ,date '2021-7-9','1' from dual

union all select 'X' ,date '2021-7-10','1' from dual

union all select 'X' ,date '2021-7-11','1' from dual

)

SELECT *

FROM d

MATCH_RECOGNIZE (

PARTITION BY type

ORDER BY dt

measures

dt as dt,

status as status

one ROW PER MATCH

PATTERN ( A )

DEFINE

A as status<>prev(status) or prev(status) is null

);

There are other ways to write , You can get the same result , Here is itpub The writing method of master Su, the moderator of the development Edition :

with d (type,dt,status)as

( select 'X' ,date '2021-7-1','1' from dual

union all select 'X' ,date '2021-7-2','1' from dual

union all select 'X' ,date '2021-7-3','0' from dual

union all select 'X' ,date '2021-7-4','0' from dual

union all select 'X' ,date '2021-7-5','1' from dual

union all select 'X' ,date '2021-7-6','0' from dual

union all select 'X' ,date '2021-7-7','0' from dual

union all select 'X' ,date '2021-7-8','0' from dual

union all select 'X' ,date '2021-7-9','1' from dual

union all select 'X' ,date '2021-7-10','1' from dual

union all select 'X' ,date '2021-7-11','1' from dual

)

SELECT *

FROM d

MATCH_RECOGNIZE (

PARTITION BY type

ORDER BY dt

ALL ROWS PER MATCH

PATTERN ( (A|{-B-})+ )

DEFINE

A as status<>last(status,1) or prev(status) is null

);

You can compare the difference between the two .

Example (2): Get the number of records whose subsequent record value is greater than the current record value , For example, the following result set

The two columns on the left are the original records , The last column is match_recognize Results after . The first record val yes 4, below 9 Condition records , All ratio 4 Big , cnt Namely 9; Second val yes 10, The next is 10 The big records are 12 and 14, cnt Namely 2, And so on .

with gen as

(select rownum as ID, round(dbms_random.value(3,15)) as val

from dual connect by level<=10

)

select * from gen

match_recognize(

order by id

measures

first(a.id) as id,

first(a.val) as val,

final count(b.*) as cnt

one row per match

after match skip to next row

pattern (a (b|c)* )

define

b as b.val>a.val,

c as c.val<=a.val

);

( There are many ways to realize this function , Here only talk about match_recognize Writing )

Example (3): Get the total salary of all employees and all subordinates

select * from

(

select level lvl, ename, sal

from scott.emp

start with mgr is null

connect by mgr = prior empno

)

match_recognize

(

measures

a.lvl lvl, a.ename ename,a.sal sal,

sum(sal) as sum_sal

after match skip to next row

pattern(a b*)

define b as lvl > a.lvl

);

Result set :

The first record lvl=1, All the records below lvl all <1,sum_sal Equivalent to the total salary of the whole company ; Article 2 record lvl=2, To the next lvl=2 Sum of all records before =10875(2975+3000+1100+3000+800 ), And so on .

Example (4) : Merge continuous intervals

with tmp(id ,page) as

(select 1 ,3 from dual union all select 2,4 from dual union all

select 4,8 from dual union all select 3,5 from dual union all

select 5,9 from dual union all select 6,16 from dual union all

select 7,15 from dual union all select 8,18 from dual

)

SELECT *

FROM tmp

MATCH_RECOGNIZE

(

ORDER BY page

MEASURES

A.page as firstpage,

LAST(page) as lastpage,

COUNT(*) cnt

ONE ROW PER MATCH

AFTER MATCH SKIP PAST LAST ROW

PATTERN (A B*)

DEFINE B AS page = PREV(page)+1

);

Result set ( On the left is before the merger ):

among : 3~5 Is a continuous 3 It's worth ; 8~9 Is a continuous 2 It's worth ...

Example (5) : Calculate continuous 3 God ( The interval between the first record and the third record shall not exceed 3 God ) And

In official account 73- Find the business peak hours sql Example ( Report development class ) in , In the message section, I added the analysis function and model Writing , Here's one more match_recognize Writing , There is no need to supplement what does not exist " God ", The simulation data is used to demonstrate the following :

with gen (id, val) as

(select 1, 3 from dual union all select 2, 2 from dual union all select 3,5 from dual union all

select 5, 3 from dual union all select 8, 2 from dual union all select 9,5 from dual union all

select 10, 3 from dual union all select 12, 2 from dual union all select 13,5 from dual union all

select 14, 3 from dual union all select 15, 2 from dual union all select 16,5 from dual union all

select 20, 3 from dual union all select 21, 2 from dual union all select 23,5 from dual

)

select bid,bid+2 as eid,sum3 from gen

match_recognize(

order by id

measures

first (a.id) as bid,

sum(val) as sum3

one row per match

after match skip to next row

pattern (A B*)

define

B as b.id<=a.id+2

);

Result set ( On the left is the raw data , On the right is match_recognize After the results of the ):

After getting the result set on the right , It can be further processed ( For example, re select top 5 etc. )

Example (6) : come from itpub Master Su's weekly question

http://www.itpub.net/thread-2117353-1-1.html

create table qz_game_log (

seq integer primary key

, log varchar2(10)

);

insert into qz_game_log values (117, 'GO');

insert into qz_game_log values (118, 'LEFT');

insert into qz_game_log values (119, 'LEFT');

insert into qz_game_log values (120, 'RIGHT');

insert into qz_game_log values (121, 'LEFT');

insert into qz_game_log values (122, 'FINISH');

insert into qz_game_log values (123, 'GO');

insert into qz_game_log values (124, 'RIGHT');

insert into qz_game_log values (125, 'RIGHT');

insert into qz_game_log values (126, 'LEFT');

insert into qz_game_log values (127, 'CRASH');

insert into qz_game_log values (128, 'GO');

insert into qz_game_log values (129, 'RIGHT');

insert into qz_game_log values (130, 'LEFT');

insert into qz_game_log values (131, 'RIGHT');

insert into qz_game_log values (132, 'LEFT');

insert into qz_game_log values (133, 'RIGHT');

insert into qz_game_log values (134, 'FINISH');

commit;

Every game is from GO Start , Then there is a series of LEFT perhaps RIGHT Move , And then to FINISH perhaps CRASH End .

The game that ends successfully is FINISH instead of CRASH End , I want to see all the successful Games LEFT/RIGHT Move steps ,

From which SEQ To which SEQ end , I also want to know how many steps , among RIGHT A few steps ,LEFT A few steps .

GO and FINISH Not counted in the game's move steps .

Required output :

FROM_SEQ TO_SEQ MOVES RIGHTS LEFTS

---------- ---------- ---------- ---------- ----------

118 121 4 1 3

129 133 5 3 2

Two ways of writing given by the original author , Worth learning :

How to write it 1)

select min(seq) as from_seq

, max(seq) as to_seq

, count(*) as moves

, count(case cls when 'RIGHT' then 1 end) as rights

, count(case cls when 'LEFT' then 1 end) as lefts

from qz_game_log

match_recognize (

measures

match_number() as mno

, classifier() as cls

ALL ROWS PER MATCH

pattern ({-GO-} (LEFT|RIGHT)+ {-FINISH-})

define

GO as log = 'GO'

, LEFT as log = 'LEFT'

, RIGHT as log = 'RIGHT'

, FINISH as log = 'FINISH'

)

GROUP BY mno

order by from_seq;

How to write it 2)

select from_seq, to_seq, moves, rights, lefts

from qz_game_log

match_recognize (

measures

min(MOVE.seq) as from_seq

, max(MOVE.seq) as to_seq

, count(MOVE.seq) as moves

, count(RIGHT.seq) as rights

, count(LEFT.seq) as lefts

one row per match

pattern (GO (LEFT|RIGHT)+ FINISH)

SUBSET

MOVE = (LEFT, RIGHT)

define

GO as log = 'GO'

, LEFT as log = 'LEFT'

, RIGHT as log = 'RIGHT'

, FINISH as log = 'FINISH'

)

order by from_seq;

How to write it 3) This is the way I try to write ( All roads lead to Rome , There should be no difference in performance ):

select * from qz_game_log

match_recognize(

order by seq

measures

least(first(l.seq) , first(r.seq) ) as from_seq,

greatest(last(l.seq) , last(r.seq) ) as to_seq,

count(l.*)+count(r.*) as moves,

count(r.*) as rights,

count(l.*) as lefts

one row per match

pattern

( strt (L|R)+ fini )

define

strt as log='GO',

L as log='LEFT',

R as log='RIGHT',

fini as log='FINISH'

);

use match_recognize There are many other cases related to line to line matching , There are also some that implement complex business logic . Here are some simple examples , Let's talk about match_recognize Have a general understanding of the usage of .

match_recognize There should be more application scenarios in the financial industry ( Such as stock analysis and suspicious transaction analysis ), After the developers are familiar with this function , You can easily use SQL Implementing complex business logic .

原网站

版权声明
本文为[Tiger Liu]所创,转载请带上原文链接,感谢
https://yzsam.com/2022/173/202206221910053487.html