SlideShare a Scribd company logo
1 of 212
Copyright © 2018, Oracle and/or its affiliates. All rights reserved.
Connor McDonald
Copyright © 2018, Oracle and/or its affiliates. All rights reserved.
3
Copyright © 2018, Oracle and/or its affiliates. All rights reserved.
4
Copyright © 2018, Oracle and/or its affiliates. All rights reserved. |
Stuff
youtube bit.ly/youtube-connor
blog bit.ly/blog-connor
twitter bit.ly/twitter-connor
400+ posts mainly on database & development
250 technical videos, new uploads every week
rants and raves on tech and the world :-)
Copyright © 2018, Oracle and/or its affiliates. All rights reserved.
etc...
facebook bit.ly/facebook-connor
linkedin bit.ly/linkedin-connor
instagram bit.ly/instagram-connor
slideshare bit.ly/slideshare-connor
Copyright © 2018, Oracle and/or its affiliates. All rights reserved.
7https://asktom.oracle.com
Copyright © 2018, Oracle and/or its affiliates. All rights reserved.
https://asktom.oracle.com/officehours
Copyright © 2017, Oracle and/or its affiliates. All rights reserved.
150 hours free access so far
9
Pattern Matching in 12c SQL
Connor McDonald
Developer Advocate
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
before we start
11
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
key point
12
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
this session is about
13
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
smart not smart ass
14
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL can do anything
15
SQL> with x( s, ind ) as
2 ( select sud, instr( sud, '.' )
3 from ( select replace(replace(
4 replace(replace(:board,'-'),'|'),' '),chr(10)) sud
5 from dual )
6 union all
7 select substr(s,1,ind-1)||z||substr(s,ind+1)
8 , instr(s,'.',ind+1)
9 from x
10 , ( select to_char( rownum ) z
11 from dual connect by rownum <= 9 ) z
12 where ind > 0
13 and not exists (
14 select null
15 from ( select rownum lp from dual
16 connect by rownum <= 9 )
17 where z = substr(s,trunc((ind-1)/9)*9+lp,1)
16
18 or z = substr(s,mod(ind-1,9)-8+lp*9,1)
19 or z = substr(s,mod(trunc((ind-1)/3),3)*3
20 +trunc((ind-1)/27)*27+lp
21 +trunc((lp-1)/3)*6,1)
22 )
23 ),
24 result as (
25 select s
26 from x
27 where ind = 0 )
28 select
29 regexp_replace(substr(s,(idx-1)*9+1,9),
30 '(...)(...)(...)',
31 '1|2|3')||
32 case when mod(idx,3)=0 then chr(10)||rpad('-',11,'-') end soln
33 from result,
34 ( select level idx
35 from dual
36 connect by level <= 9 )
17
Ack: Anton Scheffer,
https://technology.amis.nl
SQL> variable board varchar2(1000)
SQL> begin :board :=
2 '53.|.7.|...
3 6..|195|...
4 .98|...|.6.
5 -----------
6 8..|.61|..3
7 4..|8.3|..1
8 7..|.2.|..6
9 -----------
10 .6.|...|28.
11 ...|419|..5
12 ...|.8.|.79
13 ';
14 end;
18
5 3 7
6 1 9 5
9 8 6
8 6 1 3
4 8 3 1
7 2 6
6 2 8
4 1 9 5
8 7 9
SOLUTION
-----------
534|678|912
672|195|348
198|342|567
-----------
859|761|423
426|853|791
713|924|856
-----------
961|537|284
287|419|635
345|286|179
-----------
19
sud.sql
20
100%
% of developers that
will need to solve Sudoku
as part of their job
21
100%
% of developers that need
to get real sh#@t done
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
real stuff
22
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
classical problem
23
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select deptno, ename
2 from emp
3 order by 1,2;
DEPTNO ENAME
---------- ----------
10 CLARK
10 KING
10 MILLER
20 ADAMS
20 FORD
20 JONES
20 SCOTT
20 SMITH
30 ALLEN
30 BLAKE
30 JAMES
30 MARTIN
30 TURNER
30 WARD
24
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
DEPTNO MEMBERS
---------- -------------------------------------
10 CLARK,KING,MILLER
20 SMITH,JONES,SCOTT,ADAMS,FORD
30 ALLEN,WARD,MARTIN,BLAKE,TURNER,JAMES
25
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
how we used to do it
26
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select deptno , rtrim(ename,',') enames
2 from ( select deptno,ename,rn
3 from emp
4 model
5 partition by (deptno)
6 dimension by (
7 row_number() over
8 (partition by deptno order by ename) rn
9 )
10 measures (cast(ename as varchar2(40)) ename)
11 rules
12 ( ename[any]
13 order by rn desc = ename[cv()]||','||ename[cv()+1])
14 )
15 where rn = 1
16 order by deptno;
DEPTNO ENAMES
---------- ----------------------------------------
10 CLARK,KING,MILLER
20 ADAMS,FORD,JONES,SCOTT,SMITH
30 ALLEN,BLAKE,JAMES,MARTIN,TURNER,WARD
27
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select deptno,
2 substr(max(sys_connect_by_path(ename, ',')), 2) members
3 from (select deptno, ename,
4 row_number ()
5 over (partition by deptno order by empno) rn
6 from emp)
7 start with rn = 1
8 connect by prior rn = rn - 1
9 and prior deptno = deptno
10 group by deptno
11 /
DEPTNO MEMBERS
---------- ---------------------------------------------------------
30 ALLEN,WARD,MARTIN,BLAKE,TURNER,JAMES
20 SMITH,JONES,SCOTT,ADAMS,FORD
10 CLARK,KING,MILLER
28
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select deptno,
2 xmltransform
3 ( sys_xmlagg
4 ( sys_xmlgen(ename)
5 ),
6 xmltype
7 (
8 '<?xml version="1.0"?><xsl:stylesheet version="1.0"
9 xmlns:xsl="http://www.w3.org/1999/XSL/Transform">
10 <xsl:template match="/">
11 <xsl:for-each select="/ROWSET/ENAME">
12 <xsl:value-of select="text()"/>,</xsl:for-each>
13 </xsl:template>
14 </xsl:stylesheet>'
15 )
16 ).getstringval() members
17 from emp
18 group by deptno;
DEPTNO MEMBERS
---------- --------------------------------------------------------
10 CLARK,MILLER,KING,
20 SMITH,FORD,ADAMS,SCOTT,JONES,
30 ALLEN,JAMES,TURNER,BLAKE,MARTIN,WARD,
29
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> create or replace type string_agg_type as object
2 (
3 total varchar2(4000),
4
5 static function
6 ODCIAggregateInitialize(sctx IN OUT string_agg_type )
7 return number,
8
9 member function
10 ODCIAggregateIterate(self IN OUT string_agg_type ,
11 value IN varchar2 )
12 return number,
13
14 member function
15 ODCIAggregateTerminate(self IN string_agg_type,
16 returnValue OUT varchar2,
17 flags IN number)
18 return number,
19
20 member function
21 ODCIAggregateMerge(self IN OUT string_agg_type,
22 ctx2 IN string_agg_type)
23 return number
24 );
25 /
30
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
11g
31
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select deptno,
2 listagg( ename, ',')
3 within group (order by empno) members
4 from emp
5 group by deptno;
DEPTNO MEMBERS
---------- -----------------------------------------
10 CLARK,KING,MILLER
20 SMITH,JONES,SCOTT,ADAMS,FORD
30 ALLEN,WARD,MARTIN,BLAKE,TURNER,JAMES
32
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
question
solution
33
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
still challenges
34
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
example
35
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | 36
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
37
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
"I want to reward active customers…
If their transaction volume grows by 20% in a day,
or grows by 10% for 3 consecutive days,
then show me their details"
38
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select * from cust_summary
2 order by 1,2;
CUSTOMER DTE TXN_CNT
------------------------------ --------- ----------
Gerald Jones 06-FEB-17 100
Gerald Jones 07-FEB-17 130
Gerald Jones 08-FEB-17 145
Gerald Jones 09-FEB-17 200
Gerald Jones 10-FEB-17 225
Gerald Jones 11-FEB-17 255
Gerald Jones 12-FEB-17 285
Gerald Jones 13-FEB-17 315
John Smith 01-FEB-17 100
John Smith 02-FEB-17 103
John Smith 03-FEB-17 116
John Smith 04-FEB-17 129
John Smith 05-FEB-17 142
Sue Brown 06-FEB-17 50
Sue Brown 07-FEB-17 53
Sue Brown 08-FEB-17 72
...
39
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | 40
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
analytics
41
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
"I want to reward active customers…
If their transaction volume grows by 20% in a day,
or grows by 10% for 3 consecutive days,
then show me the details"
42
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select customer, dte, cumu_txns, next_txn, next_txn - cumu_txns daily_txn
2 from (
3 select customer, dte, cumu_txns
4 , lead(cumu_txns) over (
5 partition by customer order by dte
6 ) next_txn
7 from cust_summary
8 );
CUSTOMER DTE CUMU_TXNS NEXT_TXN DAILY_TXN
------------------------------ --------- ---------- ---------- ----------
Gerald Jones 06-FEB-17 100 130 30
Gerald Jones 07-FEB-17 130 145 15
Gerald Jones 08-FEB-17 145 200 55
Gerald Jones 09-FEB-17 200 225 25
Gerald Jones 10-FEB-17 225 255 30
43
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
"I want to reward active customers…
If their transaction volume grows by 20% in a day,
or grows by 10% for 3 consecutive days,
then show me the details"
44
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select customer, dte, cumu_txns, next_txn, next_txn - cumu_txns daily_txn
2 , case
3 when next_txn >= cumu_txns * 1.20 then 'FAST'
4 when next_txn >= cumu_txns * 1.10 then 'SLOW'
5 end growth_class
6 from (
7 select customer, dte, cumu_txns
8 , lead(cumu_txns) over (
9 partition by customer order by dte
10 ) next_txn
11 from cust_summary
12 );
CUSTOMER DTE CUMU_TXNS NEXT_TXN DAILY_TXN GROWTH_CLASS
------------------------------ --------- ---------- ---------- ---------- ------------
Gerald Jones 06-FEB-17 100 130 30 FAST
Gerald Jones 07-FEB-17 130 145 15 SLOW
Gerald Jones 08-FEB-17 145 200 55 FAST
Gerald Jones 09-FEB-17 200 225 25 SLOW
Gerald Jones 10-FEB-17 225 255 30 SLOW
Gerald Jones 11-FEB-17 255 285 30 SLOW
Gerald Jones 12-FEB-17 285 315 30 SLOW
45
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
"I want to reward active customers…
If their transaction volume grows by 20% in a day,
or grows by 10% for 3 consecutive days,
then show me the details"
46
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select customer, growth_class, dte, cumu_txns, next_txn, daily_txn
2 , case
3 when growth_class is not null and
4 ( lag(growth_class) over (
5 partition by customer order by dte
6 ) is null
7 or
8 lag(growth_class) over (
9 partition by customer order by dte
10 ) != growth_class
11 )
12 then dte
13 end growthstartdate
14 from (
15 select customer, dte, cumu_txns, next_txn, next_txn - cumu_txns daily_txn
16 , case
17 when next_txn >= cumu_txns * 1.20 then 'FAST'
18 when next_txn >= cumu_txns * 1.10 then 'SLOW'
19 end growth_class
20 from (
21 select customer, dte, cumu_txns
22 , lead(cumu_txns) over (
23 partition by customer order by dte
24 ) next_txn
25 from cust_summary
26 ) )
47
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select customer, growth_class, dte, cumu_txns, next_txn, daily_txn
2 , last_value(growthstartdate ignore nulls) over (
3 partition by customer, growth_class order by dte
4 rows between unbounded preceding and current row
5 ) startdate
6 from (
7 select customer, growth_class, dte, cumu_txns, next_txn, daily_txn
8 , case
9 when growth_class is not null and
10 ( lag(growth_class) over (
11 partition by customer order by dte ) is null or
12 lag(growth_class) over (
13 partition by customer order by dte
14 ) != growth_class )
15 then dte
16 end growthstartdate
17 from (
18 select customer, dte, cumu_txns, next_txn, next_txn - cumu_txns daily_txn
19 , case when next_txn >= cumu_txns * 1.20 then 'FAST'
20 when next_txn >= cumu_txns * 1.10 then 'SLOW'
21 end growth_class
22 from (
23 select customer, dte, cumu_txns
24 , lead(cumu_txns) over (partition by customer order by dte
25 ) next_txn
26 from cust_summary
27 ) ) )
28 where growth_class is not null
48
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select customer, growth_class, startdate
2 , min(cumu_txns) keep (dense_rank first order by dte) start_txn
3 , max(dte) enddate
4 , max(next_txn) keep (dense_rank last order by dte) end_txn
5 , avg(daily_txn) avg_daily_txn
6 from (
7 select customer, growth_class, dte, cumu_txns, next_txn, daily_txn
8 , last_value(growthstartdate ignore nulls) over (
9 partition by customer, growth_class order by dte
10 rows between unbounded preceding and current row
11 ) startdate
12 from (
13 select customer, growth_class, dte, cumu_txns, next_txn, daily_txn
14 , case when growth_class is not null and
15 ( lag(growth_class) over (partition by customer order by dte) is null or
16 lag(growth_class) over (partition by customer order by dte) != growth_class )
17 then dte end growthstartdate
18 from (
19 select customer, dte, cumu_txns, next_txn, next_txn - cumu_txns daily_txn
20 , case
21 when next_txn >= cumu_txns * 1.20 then 'FAST'
22 when next_txn >= cumu_txns * 1.10 then 'SLOW'
23 end growth_class
24 from (
25 select customer, dte, cumu_txns
26 , lead(cumu_txns) over (
27 partition by customer order by dte
28 ) next_txn
29 from cust_summary
30 ) ) )
31 where growth_class is not null )
32 group by customer, growth_class, startdate
33 having count(*) >= case growth_class when 'FAST' then 1 when 'SLOW' then 3 end
34 order by customer, startdate;
49
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
CUSTOMER GROWTH_CLASS STARTDATE START_TXN ENDDATE END_TXN AVG_DAILY_TXN
------------------- ---------------- --------- ---------- --------- ---------- -------------
Gerald Jones FAST 06-FEB-17 100 06-FEB-17 130 30
Gerald Jones FAST 08-FEB-17 145 08-FEB-17 200 55
Gerald Jones SLOW 09-FEB-17 200 12-FEB-17 315 28.75
John Smith SLOW 02-FEB-17 103 05-FEB-17 160 14.25
John Smith FAST 07-FEB-17 165 07-FEB-17 210 45
Sue Brown FAST 07-FEB-17 53 08-FEB-17 97 22
50
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
"easy!"
51
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | 52
W T H
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
analytics are about computation
53
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
users look for patterns
54
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
question
solution
55
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
need a syntax ...
56
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
... to describe patterns
57
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select customer, growth_class, startdate, start_txn, enddate,
2 end_txn, avg_daily_txn
3 from cust_summary
4 match_recognize (
5 partition by customer order by dte
6 measures
7 classifier() as growth_class
8 , first(dte) as startdate
9 , first(cumu_txns) as start_txn
10 , last(dte) as enddate
11 , next(cumu_txns) as end_txn
12 , (next(cumu_txns) - first(cumu_txns)) / count(*) as avg_daily_txn
13 one row per match after match skip past last row
14 pattern ( fast+ | slow{3,} )
15 define fast as next(cumu_txns) / cumu_txns >= 1.20
16 , slow as next(slow.cumu_txns) / slow.cumu_txns >= 1.10 and
17 next(slow.cumu_txns) / slow.cumu_txns < 1.20
18 )
19 order by customer, startdate;
58
regular expression
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
CUSTOMER GROWTH_CLASS STARTDATE START_TXN ENDDATE END_TXN AVG_DAILY_TXN
------------------ --------------- --------- ---------- --------- ---------- -------------
Gerald Jones FAST 06-FEB-17 100 06-FEB-17 130 30
Gerald Jones FAST 08-FEB-17 145 08-FEB-17 200 55
Gerald Jones SLOW 09-FEB-17 200 12-FEB-17 315 28.75
John Smith SLOW 02-FEB-17 103 05-FEB-17 160 14.25
John Smith FAST 07-FEB-17 165 07-FEB-17 210 45
Sue Brown FAST 07-FEB-17 53 08-FEB-17 97 22
59
3+ consecutive days, but show one row
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select customer, growth_class, startdate, start_txn, enddate,
2 end_txn, avg_daily_txn
3 from cust_summary
4 match_recognize (
5 partition by customer order by dte
6 measures
7 classifier() as growth_class
8 , first(dte) as startdate
9 , first(cumu_txns) as start_txn
10 , last(dte) as enddate
11 , next(cumu_txns) as end_txn
12 , (next(cumu_txns) - first(cumu_txns)) / count(*) as avg_daily_txn
13 one row per match after match skip past last row
14 pattern ( fast+ | slow{3,} )
15 define fast as next(cumu_txns) / cumu_txns >= 1.20
16 , slow as next(slow.cumu_txns) / slow.cumu_txns >= 1.10 and
17 next(slow.cumu_txns) / slow.cumu_txns < 1.20
18 )
19 order by customer, startdate;
60
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
done !
61
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
w t f
62
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
"chapter 1"
63
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
"Hello World" pattern match
64
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select * from t;
X
----------
1
2
3
5
6
9
10
11
16
17
19
21
30
65
find contiguous numbers
LO HI
---------- ----------
1 3
5 6
9 11
16 17
19 19
21 21
30 30
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select *
2 from t
3 match_recognize (
4 order by x
5 all rows per match
6 pattern ( contig* )
7 define contig as x = prev(x) + 1
8 );
66
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select *
2 from t
3 match_recognize (
4 order by x
5 all rows per match
6 pattern ( contig* )
7 define contig as x = prev(x) + 1
8 );
X
----------
1
2
3
5
6
9
10
11
16
17
19
21
30
67
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
68
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select *
2 from t
3 match_recognize (
4 order by x
5 all rows per match
6 pattern ( contig+ )
7 define contig as x = prev(x) + 1
8 );
X
----------
2
3
6
10
11
17
69
1 2 3
5 6
9 10 11
16 1719
21
30
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select *
2 from t
3 match_recognize (
4 order by x
5 all rows per match
6 pattern ( any_old_row contig* )
7 define
8 contig as x = prev(x) + 1,
9 any_old_row as 1=1
10 );
70
"every row is the potentially the
start of a contiguous sequence…"
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select *
2 from t
3 match_recognize (
4 order by x
5 all rows per match
6 pattern ( any_old_row contig* )
7 define
8 contig as x = prev(x) + 1,
9 any_old_row as 1=1
10 );
71
"... followed by zero or more
contiguous values"
"every row is the potentially the
start of a contiguous sequence…"
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select *
2 from t
3 match_recognize (
4 order by x
5 all rows per match
6 pattern ( any_old_row contig* )
7 define
8 contig as x = prev(x) + 1,
9 any_old_row as 1=1
10 );
72
X
----------
1
2
3
5
6
9
10
11
16
17
19
21
30
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select *
2 from t
3 match_recognize (
4 order by x
5 all rows per match
6 pattern ( any_old_row contig* )
7 define contig as x = prev(x) + 1 );
X
----------
1
2
3
5
6
9
10
11
16
17
19
21
30
73
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
"um…er…. that's just all the rows isn't it ?"
74
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
measures
75
what we want to see
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select * from t
2 match_recognize ( order by x
3 measures
4 first(x) lo
5 , last(x) hi
6 all rows per match
7 pattern ( any_old_row contig* )
8 define contig as x = prev(x) + 1 );
X LO HI
---------- ---------- ----------
1 1 1
2 1 2
3 1 3
5 5 5
6 5 6
9 9 9
10 9 10
11 9 11
16 16 16
17 16 17
19 19 19
21 21 21
30 30 30
76
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
"I only want THOSE rows …"
77
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
"…I do not want ALL of the rows …"
78
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select * from t
2 match_recognize ( order by x
3 measures
4 first(x) lo
5 , last(x) hi
6 one row per match
7 pattern ( any_old_row contig* )
8 define contig as x = prev(x) + 1 );
LO HI
---------- ----------
1 3
5 6
9 11
16 17
19 19
21 21
30 30
79
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select * from t
2 match_recognize ( order by x
3 measures
4 first(x) lo
5 , last(x) hi
6 , count(*) range
7 pattern ( any_old_row contig* )
8 define contig as x = prev(x) + 1 );
LO HI RANGE
---------- ---------- ----------
1 3 3
5 6 2
9 11 3
16 17 2
19 19 1
21 21 1
30 30 1
80
one row per match = default
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
"that is not a normal COUNT(*)"
81
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
keywords
82
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select * from t
2 match_recognize ( order by x
3 measures
4 x x
5 , first(x) lo
6 , last(x) hi
7 , prev(x) prv
8 , next(x) nxt
9 , count(*) range
10 , final last(x) fin
11 , contig.x as contig_x
12 , count(contig.*) contig_count
13 pattern ( any_old_row contig* )
14 define contig as x = prev(x) + 1
15 );
X LO HI PRV NXT RANGE FIN CONTIG_X CONTIG_COUNT
---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ------------
3 1 3 2 5 3 3 3 2
6 5 6 5 9 2 6 6 1
11 9 11 10 16 3 11 11 2
17 16 17 16 19 2 17 17 1
19 19 19 17 21 1 19 0
21 21 21 19 30 1 21 0
30 30 30 21 1 30 0
83
include the column / expression
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select * from t
2 match_recognize ( order by x
3 measures
4 x x
5 , first(x) lo
6 , last(x) hi
7 , prev(x) prv
8 , next(x) nxt
9 , count(*) range
10 , final last(x) fin
11 , contig.x as contig_x
12 , count(contig.*) contig_count
13 pattern ( any_old_row contig* )
14 define contig as x = prev(x) + 1
15 );
X LO HI PRV NXT RANGE FIN CONTIG_X CONTIG_COUNT
---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ------------
3 1 3 2 5 3 3 3 2
6 5 6 5 9 2 6 6 1
11 9 11 10 16 3 11 11 2
17 16 17 16 19 2 17 17 1
19 19 19 17 21 1 19 0
21 21 21 19 30 1 21 0
30 30 30 21 1 30 0
84
value from first row in match
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select * from t
2 match_recognize ( order by x
3 measures
4 x x
5 , first(x) lo
6 , last(x) hi
7 , prev(x) prv
8 , next(x) nxt
9 , count(*) range
10 , final last(x) fin
11 , contig.x as contig_x
12 , count(contig.*) contig_count
13 pattern ( any_old_row contig* )
14 define contig as x = prev(x) + 1
15 );
X LO HI PRV NXT RANGE FIN CONTIG_X CONTIG_COUNT
---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ------------
3 1 3 2 5 3 3 3 2
6 5 6 5 9 2 6 6 1
11 9 11 10 16 3 11 11 2
17 16 17 16 19 2 17 17 1
19 19 19 17 21 1 19 0
21 21 21 19 30 1 21 0
30 30 30 21 1 30 0
85
value from last row in match
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select * from t
2 match_recognize ( order by x
3 measures
4 x x
5 , first(x) lo
6 , last(x) hi
7 , prev(x) prv
8 , next(x) nxt
9 , count(*) range
10 , final last(x) fin
11 , contig.x as contig_x
12 , count(contig.*) contig_count
13 pattern ( any_old_row contig* )
14 define contig as x = prev(x) + 1
15 );
X LO HI PRV NXT RANGE FIN CONTIG_X CONTIG_COUNT
---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ------------
3 1 3 2 5 3 3 3 2
6 5 6 5 9 2 6 6 1
11 9 11 10 16 3 11 11 2
17 16 17 16 19 2 17 17 1
19 19 19 17 21 1 19 0
21 21 21 19 30 1 21 0
30 30 30 21 1 30 0
86
value from previous referred row
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select * from t
2 match_recognize ( order by x
3 measures
4 x x
5 , first(x) lo
6 , last(x) hi
7 , prev(x) prv
8 , next(x) nxt
9 , count(*) range
10 , final last(x) fin
11 , contig.x as contig_x
12 , count(contig.*) contig_count
13 pattern ( any_old_row contig* )
14 define contig as x = prev(x) + 1
15 );
X LO HI PRV NXT RANGE FIN CONTIG_X CONTIG_COUNT
---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ------------
3 1 3 2 5 3 3 3 2
6 5 6 5 9 2 6 6 1
11 9 11 10 16 3 11 11 2
17 16 17 16 19 2 17 17 1
19 19 19 17 21 1 19 0
21 21 21 19 30 1 21 0
30 30 30 21 1 30 0
87
value from next referred row
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select * from t
2 match_recognize ( order by x
3 measures
4 x x
5 , first(x) lo
6 , last(x) hi
7 , prev(x) prv
8 , next(x) nxt
9 , count(*) range
10 , final last(x) fin
11 , contig.x as contig_x
12 , count(contig.*) contig_count
13 pattern ( any_old_row contig* )
14 define contig as x = prev(x) + 1
15 );
X LO HI PRV NXT RANGE FIN CONTIG_X CONTIG_COUNT
---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ------------
3 1 3 2 5 3 3 3 2
6 5 6 5 9 2 6 6 1
11 9 11 10 16 3 11 11 2
17 16 17 16 19 2 17 17 1
19 19 19 17 21 1 19 0
21 21 21 19 30 1 21 0
30 30 30 21 1 30 0
88
count of rows in the match
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select * from t
2 match_recognize ( order by x
3 measures
4 x x
5 , first(x) lo
6 , last(x) hi
7 , prev(x) prv
8 , next(x) nxt
9 , count(*) range
10 , final last(x) fin
11 , contig.x as contig_x
12 , count(contig.*) contig_count
13 pattern ( any_old_row contig* )
14 define contig as x = prev(x) + 1
15 );
X LO HI PRV NXT RANGE FIN CONTIG_X CONTIG_COUNT
---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ------------
3 1 3 2 5 3 3 3 2
6 5 6 5 9 2 6 6 1
11 9 11 10 16 3 11 11 2
17 16 17 16 19 2 17 17 1
19 19 19 17 21 1 19 0
21 21 21 19 30 1 21 0
30 30 30 21 1 30 0
89
last row of match *
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select * from t
2 match_recognize ( order by x
3 measures
4 x x
5 , first(x) lo
6 , last(x) hi
7 , prev(x) prv
8 , next(x) nxt
9 , count(*) range
10 , final last(x) fin
11 , contig.x as contig_x
12 , count(contig.*) contig_count
13 pattern ( any_old_row contig* )
14 define contig as x = prev(x) + 1
15 );
X LO HI PRV NXT RANGE FIN CONTIG_X CONTIG_COUNT
---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ------------
3 1 3 2 5 3 3 3 2
6 5 6 5 9 2 6 6 1
11 9 11 10 16 3 11 11 2
17 16 17 16 19 2 17 17 1
19 19 19 17 21 1 19 0
21 21 21 19 30 1 21 0
30 30 30 21 1 30 0
90
last encountered row in 'contig'
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select * from t
2 match_recognize ( order by x
3 measures
4 x x
5 , first(x) lo
6 , last(x) hi
7 , prev(x) prv
8 , next(x) nxt
9 , count(*) range
10 , final last(x) fin
11 , contig.x as contig_x
12 , count(contig.*) contig_count
13 pattern ( any_old_row contig* )
14 define contig as x = prev(x) + 1
15 );
X LO HI PRV NXT RANGE FIN CONTIG_X CONTIG_COUNT
---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ------------
3 1 3 2 5 3 3 3 2
6 5 6 5 9 2 6 6 1
11 9 11 10 16 3 11 11 2
17 16 17 16 19 2 17 17 1
19 19 19 17 21 1 19 0
21 21 21 19 30 1 21 0
30 30 30 21 1 30 0
91
count of 'contig' rows
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
but :-)
92
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
one row per match | all rows per match
93
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select * from t
2 match_recognize ( order by x
3 measures
4 x x
5 , first(x) lo
6 , last(x) hi
7 , prev(x) prv
8 , next(x) nxt
9 , count(*) range
10 , final last(x) fin
11 , contig.x as contig_x
12 , count(contig.*) contig_count
13 ALL ROWS PER MATCH
13 pattern ( any_old_row contig* )
14 define contig as x = prev(x) + 1
15 );
94
ALL ROWS PER MATCH
- this row
- first row of match pattern
- this row
- previous row from this row
- next row from this row
- count from first to this row
- last row in the match pattern
- this 'contig' row
- count from first to this contig row
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select * from t
2 match_recognize ( order by x
3 measures
4 x x
5 , first(x) lo
6 , last(x) hi
7 , prev(x) prv
8 , next(x) nxt
9 , count(*) range
10 , final last(x) fin
11 , contig.x as contig_x
12 , count(contig.*) contig_count
13 ONE ROWS PER MATCH
13 pattern ( any_old_row contig* )
14 define contig as x = prev(x) + 1
15 );
95
ONE ROW PER MATCH
- last row of match pattern
- first row of match pattern
- last row of match pattern
- previous row from this row
- next row from this row
- count of all rows in match pattern
- last row in the match pattern
- last 'contig' row in match pattern
- count of all contig row in match pattern
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
sounds complicated …
96
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
.. sensible
97
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
there's more :-)
98
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select * from t
2 match_recognize ( order by x
3 measures
4 x x
5 , first(x) lo
6 , last(x) hi
7 , prev(x) prv
8 , next(x) nxt
9 , count(*) range
10 , final last(x) fin
11 , contig.x as contig_x
12 , count(contig.*) contig_count
13 pattern ( any_old_row contig* )
14 define
15 contig as x = prev(x) + 1
16 );
X LO HI PRV NXT RANGE FIN CONTIG_X CONTIG_COUNT
---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ------------
3 1 3 2 5 3 3 3 2
6 5 6 5 9 2 6 6 1
11 9 11 10 16 3 11 11 2
17 16 17 16 19 2 17 17 1
19 19 19 17 21 1 19 0
21 21 21 19 30 1 21 0
30 30 30 21 1 30 0
99
similar expressions
in DEFINE section
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select * from t
2 match_recognize ( order by x
3 measures ... pattern ...
4 DEFINE
5 p1 as x = 1
6 , p2 as first(x) = 1
7 , p3 as last(x) = 1
8 , p4 as prev(x) = 1
9 , p5 as next(x) = 1
10 , p6 as count(*) = 1
11 , p7 as final last(x) = 1
12 , p8 as contig.x = 1
13 , p9 as count(contig.*) = 1
14 );
100
as per ALL ROWS PER MATCH
- this row
- first row of match pattern
- this row
- previous row from this row
- next row from this row
- count from first to this row
- ILLEGAL
- this 'contig' row
- count from first to this contig row
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
review
101
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select customer, growth_class, startdate, start_txn, enddate,
2 end_txn, avg_daily_txn
3 from cust_summary
4 match_recognize (
5 partition by customer order by dte
6 measures
7 classifier() as growth_class
8 , first(dte) as startdate
9 , first(cumu_txns) as start_txn
10 , last(dte) as enddate
11 , next(cumu_txns) as end_txn
12 , (next(cumu_txns) - first(cumu_txns)) / count(*) as avg_daily_txn
13 one row per match after match skip past last row
14 pattern ( fast+ | slow{3,} )
15 define fast as next(cumu_txns) / cumu_txns >= 1.20
16 , slow as next(slow.cumu_txns) / slow.cumu_txns >= 1.10 and
17 next(slow.cumu_txns) / slow.cumu_txns < 1.20
18 )
19 order by customer, startdate;
102
SQL> select customer, growth_class, startdate, start_txn, enddate,
2 end_txn, avg_daily_txn
3 from cust_summary
4 match_recognize (
5 partition by customer order by dte
6 measures
7 classifier() as growth_class
8 , first(dte) as startdate
9 , first(cumu_txns) as start_txn
10 , last(dte) as enddate
11 , next(cumu_txns) as end_txn
12 , (next(cumu_txns) - first(cumu_txns)) / count(*) as avg_daily_txn
13 one row per match after match skip past last row
14 pattern ( fast+ | slow{3,} )
15 define fast as next(cumu_txns) / cumu_txns >= 1.20
16 , slow as next(slow.cumu_txns) / slow.cumu_txns >= 1.10 and
17 next(slow.cumu_txns) / slow.cumu_txns < 1.20
18 )
19 order by customer, startdate;
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select customer, growth_class, startdate, start_txn, enddate,
2 end_txn, avg_daily_txn
3 from cust_summary
4 match_recognize (
5 partition by customer order by dte
...
103
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select customer, growth_class, startdate, start_txn, enddate,
2 end_txn, avg_daily_txn
3 from cust_summary
4 match_recognize (
5 partition by customer order by dte
...
104
logical subsets
critical
as per analytics
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
patterns
105
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
106
SQL> select customer, growth_class, startdate, start_txn, enddate,
...
14 pattern ( fast+ | slow{3,} )
15 define fast as next(cumu_txns) / cumu_txns >= 1.20
16 , slow as next(slow.cumu_txns) / slow.cumu_txns >= 1.10 and
17 next(slow.cumu_txns) / slow.cumu_txns < 1.20
regular expression syntax
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
"If you have a text parsing problem,
you can use regular expressions…
… Now you have two problems"
- anon
107
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
*
+
?
{3}
{3,}
{3,6}
{,2}
?
108
0 or more matches
1 or more matches
0 or 1 match
exactly 3 matches
3 or more matches
between 3 and 6 matches
between 0 and 2 matches
reluctance*
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
a|b
(a b){3}c
permute a b c
^
$
{- a -}
109
a or b
3 times ( a then b ) then c
abc,acb,bac,bca,cab,cba
first row in pattern
last row in pattern (^ p+ $)
not a
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
{- a -}
110
SQL> select
...
14 pattern ( {- a -} )
15 define a = amt > 10
SQL> select
...
14 pattern ( a )
15 define a = amt <= 10
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
{- a -}
111
SQL> select
...
measures
sum(a.price)
...
14 pattern ( {- a -} )
15 define a = amt > 10
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
reluctance
112
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
"Hired, Worked, Fired"
113
http://www.kibeha.dk/2015/07/row-pattern-matching-nested-within.html
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select * from t order by 1;
SEQ COL
---------- ----------
1 Hired
2 Worked
3 Worked
4 Worked
5 Worked
6 Worked
7 Terminated
8 Hired
9 Worked
10 Worked
11 Worked
12 Worked
13 Worked
14 Terminated
15 Hired
16 Worked
17 Worked
18 Worked
19 Worked
20 Worked
21 Terminated
114
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select * from t order by 1;
SEQ COL
---------- ----------
1 Hired
2 Worked
3 Worked
4 Worked
5 Worked
6 Worked
7 Terminated
8 Hired
9 Worked
10 Worked
11 Worked
12 Worked
13 Worked
14 Terminated
15 Hired
16 Worked
17 Worked
18 Worked
19 Worked
20 Worked
21 Terminated
115
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select *
2 from t
3 match_recognize (
4 order by seq
5 measures
6 first(col) as fcol,
7 col as col,
8 first(seq) p_start,
9 last(seq) p_end,
10 count(*) tot
11 one row per match
12 pattern ( hired worked* fired )
13 define
14 hired as col = 'Hired',
15 fired as col = 'Terminated'
16 );
FCOL COL P_START P_END TOT
---------- ---------- ---------- ---------- ----------
Hired Terminated 1 21 21
116
"don't care, always true"
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | 117
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
greediness
118
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select * from t order by 1;
SEQ COL
---------- ----------
1 Hired
2 Worked
3 Worked
4 Worked
5 Worked
6 Worked
7 Terminated
8 Hired
9 Worked
10 Worked
11 Worked
12 Worked
13 Worked
14 Terminated
15 Hired
16 Worked
17 Worked
18 Worked
19 Worked
20 Worked
21 Terminated
119
pattern ( hired worked* fired )
"Cool, I have my 'hired'"
"Awesome, I got my 'worked' (ie, anything)"
"Lets chew up rows as much
as I can to see if I can find 'fired'"
"Jackpot!"
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select *
2 from t
3 match_recognize (
4 order by seq
5 measures
6 first(col) as fcol,
7 col as col,
8 first(seq) p_start,
9 last(seq) p_end,
10 count(*) tot
11 one row per match
12 pattern ( hired worked*? fired )
13 define
14 hired as col = 'Hired',
15 fired as col = 'Terminated' );
FCOL COL P_START P_END TOT
---------- ---------- ---------- ---------- ----------
Hired Terminated 1 7 7
Hired Terminated 8 14 7
Hired Terminated 15 21 7
120
reluctantly search
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
be careful
121
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select * from t order by 1;
SEQ COL
---------- ----------
1 Hired
2 Worked
3 Worked
4 Worked
5 Worked
6 Worked
7 Terminated
8 Worked
9 Worked
10 Worked
11 Worked
12 Worked
13 Worked
14 Worked
15 Worked
16 Worked
17 Worked
18 Worked
19 Worked
20 Worked
21 Worked
122
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select *
2 from t
3 match_recognize (
4 order by seq
5 measures
6 first(col) as fcol,
7 col as col,
8 first(seq) p_start,
...
ORA-4030: Out of process memory when ...
123
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select *
2 from t
3 match_recognize (
4 order by seq
5 measures
6 first(col) as fcol,
7 col as col,
8 first(seq) p_start,
9 last(seq) p_end,
10 count(*) tot
11 one row per match
12 pattern ( hired worked* fired )
13 define
14 hired as col = 'Hired',
15 worked as col = 'Worked',
15 fired as col = 'Terminated' );
124
worked+
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
“imagination is more
important than knowledge”
- Albert Einstein
125
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | 126
examples
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
"count of my subordinates"
127
http://www.kibeha.dk/2015/07/row-pattern-matching-nested-within.html
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
EMPNO ENAME REPORTS
--------- -------------------- ----------
7839 KING 13
7566 JONES 4
7788 SCOTT 1
7876 ADAMS 0
7902 FORD 1
7369 SMITH 0
7698 BLAKE 5
7499 ALLEN 0
7521 WARD 0
7654 MARTIN 0
7844 TURNER 0
7900 JAMES 0
7782 CLARK 1
7934 MILLER 0
128
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | 129
conventional style
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select empno
2 , lpad(' ', (level-1)*2) || ename as ename
3 , ( select count(*)
4 from emp sub
5 start with sub.mgr = emp.empno
6 connect by sub.mgr = prior sub.empno
7 ) reports
8 from emp
9 start with mgr is null
10 connect by mgr = prior empno
11 order siblings by empno;
EMPNO ENAME REPORTS
---------- -------------------- ----------
7839 KING 13
7566 JONES 4
7788 SCOTT 1
7876 ADAMS 0
7902 FORD 1
...
130
select count(*)
from emp sub
start with sub.mgr = emp.empno
connect by sub.mgr = prior sub.empno
select count(*)
from emp sub
start with sub.mgr = emp.empno
connect by sub.mgr = prior sub.empno
select count(*)
from emp sub
start with sub.mgr = emp.empno
connect by sub.mgr = prior sub.empno
select count(*)
from emp sub
start with sub.mgr = emp.empno
connect by sub.mgr = prior sub.empno
select count(*)
from emp sub
start with sub.mgr = emp.empno
connect by sub.mgr = prior sub.empno
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | 131
where's the pattern ?
SQL> select ...
2 from cust_summary
3 match_recognize (
4 order by ...
...
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select lvl, empno, ename, rownum as rn
2 from (
3 select level as lvl, empno, ename
4 from emp
5 start with mgr is null
6 connect by mgr = prior empno
7 order siblings by empno );
LVL EMPNO ENAME RN
---------- ---------- -------------------- ----------
1 7839 KING 1
2 7566 JONES 2
3 7788 SCOTT 3
4 7876 ADAMS 4
3 7902 FORD 5
4 7369 SMITH 6
2 7698 BLAKE 7
3 7499 ALLEN 8
3 7521 WARD 9
3 7654 MARTIN 10
3 7844 TURNER 11
3 7900 JAMES 12
2 7782 CLARK 13
3 7934 MILLER 14
132
ordering sequence
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select lvl, empno, ename, rownum as rn
2 from (
3 select level as lvl, empno, ename
4 from emp
5 start with mgr is null
6 connect by mgr = prior empno
7 order siblings by empno );
LVL EMPNO ENAME RN
---------- ---------- -------------------- ----------
1 7839 KING 1
2 7566 JONES 2
3 7788 SCOTT 3
4 7876 ADAMS 4
3 7902 FORD 5
4 7369 SMITH 6
2 7698 BLAKE 7
3 7499 ALLEN 8
3 7521 WARD 9
3 7654 MARTIN 10
3 7844 TURNER 11
3 7900 JAMES 12
2 7782 CLARK 13
3 7934 MILLER 14
133
"starting level"
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select lvl, empno, ename, rownum as rn
2 from (
3 select level as lvl, empno, ename
4 from emp
5 start with mgr is null
6 connect by mgr = prior empno
7 order siblings by empno );
LVL EMPNO ENAME RN
---------- ---------- -------------------- ----------
1 7839 KING 1
2 7566 JONES 2
3 7788 SCOTT 3
4 7876 ADAMS 4
3 7902 FORD 5
4 7369 SMITH 6
2 7698 BLAKE 7
3 7499 ALLEN 8
3 7521 WARD 9
3 7654 MARTIN 10
3 7844 TURNER 11
3 7900 JAMES 12
2 7782 CLARK 13
3 7934 MILLER 14
134
"starting level"
"next level higher
then starting level?"
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select lvl, empno, ename, rownum as rn
2 from (
3 select level as lvl, empno, ename
4 from emp
5 start with mgr is null
6 connect by mgr = prior empno
7 order siblings by empno );
LVL EMPNO ENAME RN
---------- ---------- -------------------- ----------
1 7839 KING 1
2 7566 JONES 2
3 7788 SCOTT 3
4 7876 ADAMS 4
3 7902 FORD 5
4 7369 SMITH 6
2 7698 BLAKE 7
3 7499 ALLEN 8
3 7521 WARD 9
3 7654 MARTIN 10
3 7844 TURNER 11
3 7900 JAMES 12
2 7782 CLARK 13
3 7934 MILLER 14
135
"starting level"
"next level higher
then starting level?"
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select lvl, empno, ename, rownum as rn
2 from (
3 select level as lvl, empno, ename
4 from emp
5 start with mgr is null
6 connect by mgr = prior empno
7 order siblings by empno );
LVL EMPNO ENAME RN
---------- ---------- -------------------- ----------
1 7839 KING 1
2 7566 JONES 2
3 7788 SCOTT 3
4 7876 ADAMS 4
3 7902 FORD 5
4 7369 SMITH 6
2 7698 BLAKE 7
3 7499 ALLEN 8
3 7521 WARD 9
3 7654 MARTIN 10
3 7844 TURNER 11
3 7900 JAMES 12
2 7782 CLARK 13
3 7934 MILLER 14
136
"starting level"
"next level higher
then starting level?"
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select lvl, empno, ename, rownum as rn
2 from (
3 select level as lvl, empno, ename
4 from emp
5 start with mgr is null
6 connect by mgr = prior empno
7 order siblings by empno );
LVL EMPNO ENAME RN
---------- ---------- -------------------- ----------
1 7839 KING 1
2 7566 JONES 2
3 7788 SCOTT 3
4 7876 ADAMS 4
3 7902 FORD 5
4 7369 SMITH 6
2 7698 BLAKE 7
3 7499 ALLEN 8
3 7521 WARD 9
3 7654 MARTIN 10
3 7844 TURNER 11
3 7900 JAMES 12
2 7782 CLARK 13
3 7934 MILLER 14
137
"Done! How many?"
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> with raw_data as (
2 select lvl, empno, ename, rownum as rn
3 from ( select level as lvl, empno, ename
4 from emp
5 start with mgr is null
6 connect by mgr = prior empno
7 order siblings by empno )
8 )
...
138
as before
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
...
9 select empno
10 , lpad(' ', (lvl-1)*2) || ename as ename
11 , reports
12 from raw_data
13 match_recognize (
14 order by rn
15 measures
16 starting_level.rn as rn
17 , starting_level.lvl as lvl
18 , starting_level.empno as empno
19 , starting_level.ename as ename
20 , count(higher_level.lvl) as reports
21 one row per match
22 after match skip to next row
23 pattern (starting_level higher_level*)
24 define higher_level as lvl > starting_level.lvl
25 )
26 order by rn;
139
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> with raw_data as (
2 select lvl, empno, ename, rownum as rn
3 from ( select level as lvl, empno, ename
4 from emp
5 start with mgr is null
6 connect by mgr = prior empno
7 order siblings by empno )
8 )
9 select empno
10 , lpad(' ', (lvl-1)*2) || ename as ename
11 , reports
12 from raw_data
13 match_recognize (
14 order by rn
15 measures
16 starting_level.rn as rn
17 , starting_level.lvl as lvl
18 , starting_level.empno as empno
19 , starting_level.ename as ename
20 , count(higher_level.lvl) as reports
21 one row per match
22 pattern (starting_level higher_level*)
23 define higher_level as lvl > starting_level.lvl
24 )
25 order by rn;
EMPNO ENAME REPORTS
---------- -------------------- ----------
7839 KING 13
140
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | 141
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select lvl, empno, ename, rownum as rn
2 from (
3 select level as lvl, empno, ename
4 from emp
5 start with mgr is null
6 connect by mgr = prior empno
7 order siblings by empno );
LVL EMPNO ENAME RN
---------- ---------- -------------------- ----------
1 7839 KING 1
2 7566 JONES 2
3 7788 SCOTT 3
4 7876 ADAMS 4
3 7902 FORD 5
4 7369 SMITH 6
2 7698 BLAKE 7
3 7499 ALLEN 8
3 7521 WARD 9
3 7654 MARTIN 10
3 7844 TURNER 11
3 7900 JAMES 12
2 7782 CLARK 13
3 7934 MILLER 14
142
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select lvl, empno, ename, rownum as rn
2 from (
3 select level as lvl, empno, ename
4 from emp
5 start with mgr is null
6 connect by mgr = prior empno
7 order siblings by empno );
LVL EMPNO ENAME RN
---------- ---------- -------------------- ----------
1 7839 KING 1
2 7566 JONES 2
3 7788 SCOTT 3
4 7876 ADAMS 4
3 7902 FORD 5
4 7369 SMITH 6
2 7698 BLAKE 7
3 7499 ALLEN 8
3 7521 WARD 9
3 7654 MARTIN 10
3 7844 TURNER 11
3 7900 JAMES 12
2 7782 CLARK 13
3 7934 MILLER 14
143
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
"done!"
144
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
...
9 select empno
10 , lpad(' ', (lvl-1)*2) || ename as ename
11 , reports
12 from raw_data
13 match_recognize (
14 order by rn
15 measures
16 starting_level.rn as rn
17 , starting_level.lvl as lvl
18 , starting_level.empno as empno
19 , starting_level.ename as ename
20 , count(higher_level.lvl) as reports
21 one row per match
22 after match skip to next row
23 pattern (starting_level higher_level*)
24 define higher_level as lvl > starting_level.lvl
25 )
26 order by rn;
145
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> with raw_data as (
...
9 select empno
10 , lpad(' ', (lvl-1)*2) || ename as ename
11 , reports
12 from raw_data
13 match_recognize (
14 order by rn
15 measures
16 starting_level.rn as rn
17 , starting_level.lvl as lvl
18 , starting_level.empno as empno
19 , starting_level.ename as ename
20 , count(higher_level.lvl) as reports
21 one row per match
22 after match skip to next row
23 pattern (starting_level higher_level*)
24 define higher_level as lvl > starting_level.lvl
25 )
26 order by rn;
EMPNO ENAME REPORTS
---------- -------------------- ----------
7839 KING 13
7566 JONES 4
7788 SCOTT 1
7876 ADAMS 0
7902 FORD 1
7369 SMITH 0
7698 BLAKE 5
7499 ALLEN 0
...
146
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | 147
the power of a single SQL
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |148
select ename
from emp
where empno = :1
select sum(...)
from emp, dept
group by ...
select min(..)
keep ( dense_rank ) ...
from emp
...
select ...
from emp
match_recognize
measures
define
...
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | 149
what if it doesn't work ?
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | 150
"What I need" "Hell yeah!"
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | 151
3GL ... we debug
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
procedure check_auto_no_new_questions
is
l_app_controls_rec ate_application_controls%rowtype;
l_auto_no_new_limit number;
l_new_never_read_cnt number;
begin
msg('Checking metadata');
select *
into l_app_controls_rec
from ate_application_controls
where application_code = 'NONEW';
if l_app_controls_rec.enabled = 'Y'
then
msg('NONEW');
return;
end if;
msg('l_new_never_read_cnt='||l_new_never_read_cnt );
msg('l_auto_no_new_limit ='||l_new_never_read_cnt );
if l_new_never_read_cnt >= l_auto_no_new_limit
then
msg('Turning off settings');
update ate_application_controls
set enabled = 'Y'
where application_code = 'NONEW';
...
152
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select customer, growth_class, startdate, start_txn, enddate,
2 end_txn, avg_daily_txn
3 from cust_summary
4 match_recognize (
5 partition by customer order by dte
6 measures
7 final last(dte) as termdate
8 , first(dte) as startdate
9 , first(cumu_txns) as start_txn
10 , last(dte) as enddate
11 , next(cumu_txns) as end_txn
12 , (next(cumu_txns) - first(cumu_txns)) / count(*) as avg_daily_txn
13 one row per match after match skip past last row
14 pattern ( fast+ | slow{3,} )
15 define fast as next(cumu_txns) / cumu_txns >= 1.20
16 , slow as next(slow.cumu_txns) / slow.cumu_txns >= 1.10 and
17 next(slow.cumu_txns) / slow.cumu_txns < 1.20
18 )
19 order by customer, startdate;
153
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | 154
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
match_number()
155
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
"Hello World"
156
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select * from t
2 match_recognize ( order by x
3 measures
4 first(x) lo
5 , last(x) hi
6 , count(*) range
7 one row per match
8 pattern ( any_old_row contig* )
9 define contig as x = prev(x) + 1 );
LO HI RANGE
---------- ---------- ----------
1 3 3
5 6 2
9 11 3
16 17 2
19 19 1
21 21 1
30 30 1
157
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select * from t
2 match_recognize ( order by x
3 measures
4 first(x) lo
5 , last(x) hi
6 , count(*) range
7 , match_number() as mn
8 all rows per match
9 pattern ( any_old_row contig* )
10 define contig as x = prev(x) + 1 );
X LO HI RANGE MN
---------- ---------- ---------- ---------- ----------
1 1 1 1 1
2 1 2 2 1
3 1 3 3 1
5 5 5 1 2
6 5 6 2 2
9 9 9 1 3
10 9 10 2 3
11 9 11 3 3
16 16 16 1 4
17 16 17 2 4
19 19 19 1 5
21 21 21 1 6
30 30 30 1 7
158
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
classifier()
159
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select * from t
2 match_recognize ( order by x
3 measures
4 first(x) lo
5 , last(x) hi
6 , count(*) range
7 , match_number() as mn
8 , classifier() as cl
9 all rows per match
10 pattern ( any_old_row contig* )
11 define contig as x = prev(x) + 1 );
X LO HI RANGE MN CL
---------- ---------- ---------- ---------- ---------- -------------
1 1 1 1 1 ANY_OLD_ROW
2 1 2 2 1 CONTIG
3 1 3 3 1 CONTIG
5 5 5 1 2 ANY_OLD_ROW
6 5 6 2 2 CONTIG
9 9 9 1 3 ANY_OLD_ROW
10 9 10 2 3 CONTIG
11 9 11 3 3 CONTIG
16 16 16 1 4 ANY_OLD_ROW
17 16 17 2 4 CONTIG
19 19 19 1 5 ANY_OLD_ROW
21 21 21 1 6 ANY_OLD_ROW
30 30 30 1 7 ANY_OLD_ROW
160
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
not just debugging
161
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
useful for grouping
162
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
"groupings of decline in expenditure"
163
http://www.kibeha.dk/2015/07/row-pattern-matching-nested-within.html
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select * from company_sal order by start_date desc;
START_DAT EXPENDITURE
--------- -----------
01-JAN-16 12880.45
01-JUL-15 12880.45
01-JUL-12 12880.45
01-FEB-12 12880.45
01-JUL-11 13421.7
01-JUL-10 12880.45
16-JUN-10 12880.45
01-APR-10 13421.7
01-NOV-09 12881.39
01-JUL-09 12361.93
01-JUL-08 12361.93
01-APR-08 12361.93
01-JUL-07 11843.41
01-JUL-06 11843.41
01-MAY-06 11843.41
01-APR-06 11843.41
01-JUL-05 11324.9
01-JUL-04 11324.9
01-MAY-04 11324.9
01-APR-04 11324.9
01-JAN-04 10806.37
01-JUL-02 10806.37
16-APR-02 10806.37
164
GRP
----------
1
1
1
1
2
2
2
3
3
3
3
3
3
3
3
3
3
3
3
3
3
3
3
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select * from company_sal
2 match_recognize (
3 order by start_date desc
4 measures
5 match_number() grp
6 all rows per match
7 pattern ( always_true headin_down* )
8 define
9 headin_down as (
10 headin_down.expenditure <= prev(headin_down.expenditure)
11 )
12 )
13 order by start_date desc ;
165
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select * from company_sal
2 match_recognize (
3 order by start_date desc
4 measures
5 match_number() grp
6 all rows per match
7 pattern ( always_true headin_down* )
8 define
9 headin_down as (
10 headin_down.expenditure <= prev(headin_down.expenditure)
11 )
12 ) order by start_date desc ;
START_DAT GRP EXPENDITURE
--------- ---------- -----------
01-JAN-16 1 12880.45
01-JUL-15 1 12880.45
01-JUL-12 1 12880.45
01-FEB-12 1 12880.45
01-JUL-11 2 13421.7
01-JUL-10 2 12880.45
16-JUN-10 2 12880.45
01-APR-10 3 13421.7
01-NOV-09 3 12881.39
01-JUL-09 3 12361.93
01-JUL-08 3 12361.93
01-APR-08 3 12361.93
...
01-JUL-02 3 10806.37
16-APR-02 3 10806.37
166
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
aggregates as patterns
167
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
"If customers hit their minimum shipping target,
ship that batch now. Otherwise ship their stuff
after 30 days"
168
http://www.kibeha.dk/2015/07/row-pattern-matching-nested-within.html
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> desc CUST
Name Null? Type
----------------------------- -------- ----------------
CUST_ID NUMBER(38)
CUST_NAME VARCHAR2(30)
MIN_SHIP_VALUE NUMBER(38)
SQL> desc CUST_ORDERS
Name Null? Type
----------------------------- -------- ----------------
CUST_ID NUMBER
ORDER_NO NUMBER
AMT NUMBER(38)
SHIP_DATE DATE
169
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select * from cust;
CUST_ID CUST_NAME MIN_SHIP_VALUE
---------- ------------------------------ --------------
1 Cust A 350
2 Cust B 750
SQL> select *
2 from cust_orders co
3 order by cust_id, ship_date, order_no;
CUST_ID ORDER_NO AMT SHIP_DATE
---------- ---------- ---------- ---------
1 11 100 31-JAN-17
1 13 10 10-FEB-17
1 12 250 11-FEB-17
1 21 1000 21-FEB-17
1 31 4000 31-MAR-17
2 41 175 31-JAN-17
2 51 100 10-FEB-17
2 42 500 11-FEB-17
2 52 1000 21-FEB-17
2 61 100 31-MAR-17
170
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select * from cust;
CUST_ID CUST_NAME MIN_SHIP_VALUE
---------- ------------------------------ --------------
1 Cust A 350
2 Cust B 750
SQL> select *
2 from cust_orders co
3 order by cust_id, ship_date, order_no;
CUST_ID ORDER_NO AMT SHIP_DATE
---------- ---------- ---------- ---------
1 11 100 31-JAN-17
1 13 10 10-FEB-17
1 12 250 11-FEB-17
1 21 1000 21-FEB-17
1 31 4000 31-MAR-17
2 41 175 31-JAN-17
2 51 100 10-FEB-17
2 42 500 11-FEB-17
2 52 1000 21-FEB-17
2 61 100 31-MAR-17
171
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select * from cust;
CUST_ID CUST_NAME MIN_SHIP_VALUE
---------- ------------------------------ --------------
1 Cust A 350
2 Cust B 750
SQL> select *
2 from cust_orders co
3 order by cust_id, ship_date, order_no;
CUST_ID ORDER_NO AMT SHIP_DATE
---------- ---------- ---------- ---------
1 11 100 31-JAN-17
1 13 10 10-FEB-17
1 12 250 11-FEB-17
1 21 1000 21-FEB-17
1 31 4000 31-MAR-17
2 41 175 31-JAN-17
2 51 100 10-FEB-17
2 42 500 11-FEB-17
2 52 1000 21-FEB-17
2 61 100 31-MAR-17
172
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
pattern
173
"any number under the shipping limit"
UNDER_LIMIT*
"then hit/exceed the shipping limit"
OVER_LIMIT
"some might never hit the shipping limit"
{0,1}
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
definitions
174
UNDER_LIMIT
OVER_LIMIT
"rolling" sum(amt) < cust.min_ship_limit
"rolling" sum(amt) >= cust.min_ship_limit
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
recall
175
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select * from t
2 match_recognize ( order by x
3 measures ... pattern ...
4 DEFINE
5 p1 as x = 1
6 , p2 as first(x) = 1
7 , p3 as last(x) = 1
8 , p4 as prev(x) = 1
9 , p5 as next(x) = 1
10 , p6 as count(*) = 1
11 , p7 as final last(x) = 1
12 , p8 as contig.x = 1
13 , p9 as count(contig.*) = 1
14 );
176
as per ALL ROWS PER MATCH
- this row
- first row of match pattern
- this row
- previous row from this row
- next row from this row
- count from first to this row
- ILLEGAL
- this 'contig' row
- count from first to this contig row
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select * from (
2 select co.*, c.min_ship_value
3 from cust c, cust_orders co
4 where c.cust_id = co.cust_id
5 )
6 match_recognize (
7 partition by cust_id
8 order by ship_date, order_no
9 measures
10 match_number() as mno,
11 classifier() as cls,
12 sum(amt) as tot
13 all rows per match
14 pattern ( under_limit* over_limit{0,1} )
15 define
16 under_limit as sum(amt) < min_ship_value,
17 over_limit as sum(amt) >= min_ship_value );
CUST_ID SHIP_DATE ORDER_NO MNO CLS TOT AMT MIN_SHIP_VALUE
---------- --------- ---------- ----- --------------- ---------- ---------- --------------
1 31-JAN-17 11 1 UNDER_LIMIT 100 100 350
1 10-FEB-17 13 1 UNDER_LIMIT 110 10 350
1 11-FEB-17 12 1 OVER_LIMIT 360 250 350
1 21-FEB-17 21 2 OVER_LIMIT 1000 1000 350
1 31-MAR-17 31 3 OVER_LIMIT 4000 4000 350
2 31-JAN-17 41 1 UNDER_LIMIT 175 175 750
2 10-FEB-17 51 1 UNDER_LIMIT 275 100 750
2 11-FEB-17 42 1 OVER_LIMIT 775 500 750
2 21-FEB-17 52 2 OVER_LIMIT 1000 1000 750
2 31-MAR-17 61 3 UNDER_LIMIT 100 100 750
177
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
"If customers hit their minimum shipping target,
ship that batch now. Otherwise ship their stuff
after 30 days"
178
http://www.kibeha.dk/2015/07/row-pattern-matching-nested-within.html
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select * from (
2 select co.*, c.min_ship_value
3 from cust c, cust_orders co
4 where c.cust_id = co.cust_id
5 )
6 match_recognize (
7 partition by cust_id
8 order by ship_date, order_no
9 measures
10 match_number() as mno,
11 classifier() as cls,
12 sum(amt) as tot,
13 nvl(final last(over_limit.ship_date), last(ship_date)+30) last_ship_date
14 all rows per match
15 pattern ( under_limit* over_limit{0,1} )
16 define
17 under_limit as sum(amt) < min_ship_value,
18 over_limit as sum(amt) >= min_ship_value );
179
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
pattern aggregates as measures
180
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
"W patterns in sales transactions"
181
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |182
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |183
slope1 = amt < prev(amt)
slope2 = amt > prev(amt)
slope3 = amt < prev(amt)
slope4 = amt < prev(amt)
pattern = ( slope1+ slope2+ slope3+ slope4+ )
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
"average AMT in the matched W"
184
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |185
slope1 = amt < prev(amt)
slope2 = amt > prev(amt)
slope3 = amt < prev(amt)
slope4 = amt < prev(amt)
pattern = ( slope1+ slope2+ slope3+ slope4+ )
measures
avg(amt) as w_average
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
"average AMT in first downward slide"
186
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |187
slope1 = amt < prev(amt)
slope2 = amt > prev(amt)
slope3 = amt < prev(amt)
slope4 = amt < prev(amt)
pattern = ( slope1+ slope2+ slope3+ slope4+ )
measures
avg(slope1.amt) as slide_avg
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
pattern subsets
188
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
"average AMT in first V of the W"
189
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |190
slope1 = amt < prev(amt)
slope2 = amt > prev(amt)
slope3 = amt < prev(amt)
slope4 = amt < prev(amt)
pattern = ( slope1+ slope2+ slope3+ slope4+ )
subset s1s2 = ( slope1,slope2)
measures
avg(s1s2.amt) as slide_avg
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
pattern aggregates as predicates
191
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
"W patterns in sales transactions,
capped at 7 days"
192
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |193
slope1 = amt < prev(amt)
slope2 = amt > prev(amt)
slope3 = amt < prev(amt)
slope4 = amt < prev(amt) and
slope4.dte - first(slope1.dte) < 7
Apr 3 Apr 8
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
not so obvious patterns
194
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select * from t
2 order by sample_result_key, result_date;
SAMPLE_RESULT_KEY RESULT_DA RESULT_VALUE
----------------- --------- ------------
1 01-JUN-14 4
1 03-JUN-14 5
1 06-JUN-14 4
1 07-JUN-14 3
1 09-JUN-14 7.2
1 14-JUN-14 8
1 15-JUN-14 10
1 17-JUN-14 0
2 01-JUL-14 11.55
2 03-JUL-14 11.35
2 06-JUL-14 5.43
2 07-JUL-14 7.74
2 09-JUL-14 7.27
2 14-JUL-14 7.84
2 15-JUL-14 9.54
2 17-JUL-14 10.42
195
"For the maximum date
per sample,
return the value.
But if its zero,
return the lowest value
within the last 7 days
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select * from t
2 order by sample_result_key, result_date desc;
SAMPLE_RESULT_KEY RESULT_DA RESULT_VALUE
----------------- --------- ------------
1 17-JUN-14 0
1 15-JUN-14 10
1 14-JUN-14 8
1 09-JUN-14 7.2
1 07-JUN-14 3
1 06-JUN-14 4
1 03-JUN-14 5
1 01-JUN-14 4
2 17-JUL-14 10.42
2 15-JUL-14 9.54
2 14-JUL-14 7.84
2 09-JUL-14 7.27
2 07-JUL-14 7.74
2 06-JUL-14 5.43
2 03-JUL-14 11.35
2 01-JUL-14 11.55
196
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
pattern (^starting_pos boundary*)
define
boundary as starting_pos.result_value = 0 and
result_date >= starting_pos.result_date - 7
and result_value = min(result_value)
197
start with first row per sample
when that row is zero,
match forward up to 7 days
and pick the lowest value
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select * from t
2 match_recognize(
3 partition by sample_result_key
4 order by result_date desc
5 measures
6 match_number() as mn,
7 classifier() as cl,
8 starting_pos.result_date rd1,
9 result_value rv1
10 all rows per match
11 pattern (^starting_pos boundary*)
12 define
13 boundary as starting_pos.result_value = 0 and
14 result_date >= starting_pos.result_date - 7
15 and result_value = min(result_value)
16 );
SAMPLE_RESULT_KEY RESULT_DA MN CL RD1 RV1 RESULT_VALUE
----------------- --------- ---------- -------------- --------- ---------- ------------
1 17-JUN-14 1 STARTING_POS 17-JUN-14 0 0
2 17-JUL-14 1 STARTING_POS 17-JUL-14 10.42 10.42
198
includes the zero row
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
pattern (^starting_pos boundary*)
define
not_so_restrictive as starting_pos.result_value = 0 and
result_date >= starting_pos.result_date - 7,
boundary as starting_pos.result_value = 0 and
result_date >= starting_pos.result_date - 7
and result_value = min(result_value)
199
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select * from t
2 match_recognize(
3 partition by sample_result_key
4 order by result_date desc
5 measures
6 match_number() as mn,
7 classifier() as cl,
8 starting_pos.result_date rd1,
9 result_value rv1
10 all rows per match
11 pattern (^starting_pos (boundary|not_so_restrictive)*)
12 define
13 not_so_restrictive as starting_pos.result_value = 0 and
14 result_date >= starting_pos.result_date - 7,
15 boundary as starting_pos.result_value = 0 and
16 result_date >= starting_pos.result_date - 7 and
17 result_value = min(result_value)
18 );
SAMPLE_RESULT_KEY RESULT_DA MN CL RD1 RV1 RESULT_VALUE
----------------- --------- ---------- -------------------- --------- ---------- ------------
1 17-JUN-14 1 STARTING_POS 17-JUN-14 0 0
1 15-JUN-14 1 NOT_SO_RESTRICTIVE 17-JUN-14 10 10
1 14-JUN-14 1 NOT_SO_RESTRICTIVE 17-JUN-14 8 8
2 17-JUL-14 1 STARTING_POS 17-JUL-14 10.42 10.42
200
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select * from t
2 match_recognize(
3 partition by sample_result_key
4 order by result_date desc
5 measures
6 match_number() as mn,
7 classifier() as cl,
8 starting_pos.result_date rd1,
9 result_value rv1
10 all rows per match
11 pattern (^starting_pos (boundary|not_so_restrictive)*)
12 define
13 not_so_restrictive as starting_pos.result_value = 0 and
14 result_date >= starting_pos.result_date - 7,
15 boundary as starting_pos.result_value = 0 and
16 result_date >= starting_pos.result_date - 7 and
17 result_value = min(result_value)
18 );
SAMPLE_RESULT_KEY MN CL RD1 RV1
----------------- ---------- -------------------- --------- ----------
1 1 NOT_SO_RESTRICTIVE 17-JUN-14 8
2 1 STARTING_POS 17-JUL-14 10.42
201
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
202
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
"Divides a set of weights into 3 equi-sized buckets"
203
https://stewashton.wordpress.com/2014/06/06/bin-fitting-problems-with-sql/
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select * from t;
KG
----------
1
3
4
6
7
8
11
12
13
14
17
18
19
204
1
3
4
6
7
8
11
12
13
14
17
18
19
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
pattern ( (bin1|bin2|bin3)*
)
define
bin1 as count(bin1.*) = 1
or
sum(bin1.kg) <= least(sum(bin2.kg), sum(bin3.kg)
, bin2 as count(bin2.*) = 1
or
sum(bin2.kg)-bin2.kg <= sum(bin3.kg)
205
I will want 3 bins
(matching my as yet unknown rules)
the bin is empty
- bin1.kg
my bin has less than either
of the other two bins
... so far
use my bin if ...
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select *
2 from t
3 match_recognize (
4 order by kg desc
5 measures
6 classifier() bin#,
7 sum(bin1.kg) bin1,
8 sum(bin2.kg) bin2,
9 sum(bin3.kg) bin3
10 all rows per match
11 pattern (
12 (bin1|bin2|bin3)*
13 )
14 define
15 bin1 as count(bin1.*) = 1 or
16 sum(bin1.kg)-bin1.kg <= least(sum(bin2.kg), sum(bin3.kg))
17 , bin2 as count(bin2.*) = 1 or
18 sum(bin2.kg)-bin2.kg <= sum(bin3.kg)
19 );
206
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
KG BIN# BIN1 BIN2 BIN3
---------- ------ ---------- ---------- ----------
19 BIN1 19
18 BIN2 19 18
17 BIN3 19 18 17
14 BIN3 19 18 31
13 BIN2 19 31 31
12 BIN1 31 31 31
11 BIN1 42 31 31
8 BIN2 42 39 31
7 BIN3 42 39 38
6 BIN3 42 39 44
4 BIN2 42 43 44
3 BIN1 45 43 44
1 BIN2 45 44 44
207
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
SQL> select *
2 from t
3 match_recognize (
4 order by kg desc
5 measures
6 sum(bin1.kg) bin1,
7 sum(bin2.kg) bin2,
8 sum(bin3.kg) bin3
9 pattern (
10 (bin1|bin2|bin3)*
11 )
12 define
13 bin1 as count(bin1.*) = 1 or
14 sum(bin1.kg)-bin1.kg <= least(sum(bin2.kg), sum(bin3.kg))
15 , bin2 as count(bin2.*) = 1 or
16 sum(bin2.kg)-bin2.kg <= sum(bin3.kg)
17 );
BIN1 BIN2 BIN3
---------- ---------- ----------
45 44 44
208
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | 209
wrap up
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | 210
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | 211
be patient
Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |
Enjoy the day!
youtube bit.ly/youtube-connor
blog bit.ly/blog-connor
twitter bit.ly/twitter-connor
400+ posts mainly on database & development
250 technical videos, new uploads every week
rants and raves on tech and the world :-)

More Related Content

Similar to Wellington APAC Groundbreakers tour - SQL Pattern Matching

Pattern Matching with SQL - APEX World Rotterdam 2019
Pattern Matching with SQL - APEX World Rotterdam 2019Pattern Matching with SQL - APEX World Rotterdam 2019
Pattern Matching with SQL - APEX World Rotterdam 2019Connor McDonald
 
Latin America Tour 2019 - pattern matching
Latin America Tour 2019 - pattern matchingLatin America Tour 2019 - pattern matching
Latin America Tour 2019 - pattern matchingConnor McDonald
 
Latin America Tour 2019 - 10 great sql features
Latin America Tour 2019  - 10 great sql featuresLatin America Tour 2019  - 10 great sql features
Latin America Tour 2019 - 10 great sql featuresConnor McDonald
 
Perth APAC Groundbreakers tour - SQL Techniques
Perth APAC Groundbreakers tour - SQL TechniquesPerth APAC Groundbreakers tour - SQL Techniques
Perth APAC Groundbreakers tour - SQL TechniquesConnor McDonald
 
Sangam 18 - Great Applications with Great SQL
Sangam 18 - Great Applications with Great SQLSangam 18 - Great Applications with Great SQL
Sangam 18 - Great Applications with Great SQLConnor McDonald
 
SQL techniques for faster applications
SQL techniques for faster applicationsSQL techniques for faster applications
SQL techniques for faster applicationsConnor McDonald
 
Sangam 2019 - The Latest Features
Sangam 2019 - The Latest FeaturesSangam 2019 - The Latest Features
Sangam 2019 - The Latest FeaturesConnor McDonald
 
Wellington APAC Groundbreakers tour - Upgrading to the 12c Optimizer
Wellington APAC Groundbreakers tour - Upgrading to the 12c OptimizerWellington APAC Groundbreakers tour - Upgrading to the 12c Optimizer
Wellington APAC Groundbreakers tour - Upgrading to the 12c OptimizerConnor McDonald
 
Connor McDonald 11g for developers
Connor McDonald 11g for developersConnor McDonald 11g for developers
Connor McDonald 11g for developersInSync Conference
 
Melbourne Groundbreakers Tour - Upgrading without risk
Melbourne Groundbreakers Tour - Upgrading without riskMelbourne Groundbreakers Tour - Upgrading without risk
Melbourne Groundbreakers Tour - Upgrading without riskConnor McDonald
 
Sangam 18 - The New Optimizer in Oracle 12c
Sangam 18 - The New Optimizer in Oracle 12cSangam 18 - The New Optimizer in Oracle 12c
Sangam 18 - The New Optimizer in Oracle 12cConnor McDonald
 
Analytic functions in Oracle SQL - BIWA 2017
Analytic functions in Oracle SQL - BIWA 2017Analytic functions in Oracle SQL - BIWA 2017
Analytic functions in Oracle SQL - BIWA 2017Connor McDonald
 
The Five Best Things To Happen To SQL
The Five Best Things To Happen To SQLThe Five Best Things To Happen To SQL
The Five Best Things To Happen To SQLConnor McDonald
 
18c and 19c features for DBAs
18c and 19c features for DBAs18c and 19c features for DBAs
18c and 19c features for DBAsConnor McDonald
 
OpenWorld 2018 - Pagination
OpenWorld 2018 - PaginationOpenWorld 2018 - Pagination
OpenWorld 2018 - PaginationConnor McDonald
 
OOW19 - Ten Amazing SQL features
OOW19 - Ten Amazing SQL featuresOOW19 - Ten Amazing SQL features
OOW19 - Ten Amazing SQL featuresConnor McDonald
 
SQL and PLSQL features for APEX Developers
SQL and PLSQL features for APEX DevelopersSQL and PLSQL features for APEX Developers
SQL and PLSQL features for APEX DevelopersConnor McDonald
 
Riyaj: why optimizer_hates_my_sql_2010
Riyaj: why optimizer_hates_my_sql_2010Riyaj: why optimizer_hates_my_sql_2010
Riyaj: why optimizer_hates_my_sql_2010Riyaj Shamsudeen
 
UKOUG 2019 - SQL features
UKOUG 2019 - SQL featuresUKOUG 2019 - SQL features
UKOUG 2019 - SQL featuresConnor McDonald
 

Similar to Wellington APAC Groundbreakers tour - SQL Pattern Matching (20)

Pattern Matching with SQL - APEX World Rotterdam 2019
Pattern Matching with SQL - APEX World Rotterdam 2019Pattern Matching with SQL - APEX World Rotterdam 2019
Pattern Matching with SQL - APEX World Rotterdam 2019
 
Latin America Tour 2019 - pattern matching
Latin America Tour 2019 - pattern matchingLatin America Tour 2019 - pattern matching
Latin America Tour 2019 - pattern matching
 
Latin America Tour 2019 - 10 great sql features
Latin America Tour 2019  - 10 great sql featuresLatin America Tour 2019  - 10 great sql features
Latin America Tour 2019 - 10 great sql features
 
Perth APAC Groundbreakers tour - SQL Techniques
Perth APAC Groundbreakers tour - SQL TechniquesPerth APAC Groundbreakers tour - SQL Techniques
Perth APAC Groundbreakers tour - SQL Techniques
 
KScope19 - SQL Features
KScope19 - SQL FeaturesKScope19 - SQL Features
KScope19 - SQL Features
 
Sangam 18 - Great Applications with Great SQL
Sangam 18 - Great Applications with Great SQLSangam 18 - Great Applications with Great SQL
Sangam 18 - Great Applications with Great SQL
 
SQL techniques for faster applications
SQL techniques for faster applicationsSQL techniques for faster applications
SQL techniques for faster applications
 
Sangam 2019 - The Latest Features
Sangam 2019 - The Latest FeaturesSangam 2019 - The Latest Features
Sangam 2019 - The Latest Features
 
Wellington APAC Groundbreakers tour - Upgrading to the 12c Optimizer
Wellington APAC Groundbreakers tour - Upgrading to the 12c OptimizerWellington APAC Groundbreakers tour - Upgrading to the 12c Optimizer
Wellington APAC Groundbreakers tour - Upgrading to the 12c Optimizer
 
Connor McDonald 11g for developers
Connor McDonald 11g for developersConnor McDonald 11g for developers
Connor McDonald 11g for developers
 
Melbourne Groundbreakers Tour - Upgrading without risk
Melbourne Groundbreakers Tour - Upgrading without riskMelbourne Groundbreakers Tour - Upgrading without risk
Melbourne Groundbreakers Tour - Upgrading without risk
 
Sangam 18 - The New Optimizer in Oracle 12c
Sangam 18 - The New Optimizer in Oracle 12cSangam 18 - The New Optimizer in Oracle 12c
Sangam 18 - The New Optimizer in Oracle 12c
 
Analytic functions in Oracle SQL - BIWA 2017
Analytic functions in Oracle SQL - BIWA 2017Analytic functions in Oracle SQL - BIWA 2017
Analytic functions in Oracle SQL - BIWA 2017
 
The Five Best Things To Happen To SQL
The Five Best Things To Happen To SQLThe Five Best Things To Happen To SQL
The Five Best Things To Happen To SQL
 
18c and 19c features for DBAs
18c and 19c features for DBAs18c and 19c features for DBAs
18c and 19c features for DBAs
 
OpenWorld 2018 - Pagination
OpenWorld 2018 - PaginationOpenWorld 2018 - Pagination
OpenWorld 2018 - Pagination
 
OOW19 - Ten Amazing SQL features
OOW19 - Ten Amazing SQL featuresOOW19 - Ten Amazing SQL features
OOW19 - Ten Amazing SQL features
 
SQL and PLSQL features for APEX Developers
SQL and PLSQL features for APEX DevelopersSQL and PLSQL features for APEX Developers
SQL and PLSQL features for APEX Developers
 
Riyaj: why optimizer_hates_my_sql_2010
Riyaj: why optimizer_hates_my_sql_2010Riyaj: why optimizer_hates_my_sql_2010
Riyaj: why optimizer_hates_my_sql_2010
 
UKOUG 2019 - SQL features
UKOUG 2019 - SQL featuresUKOUG 2019 - SQL features
UKOUG 2019 - SQL features
 

More from Connor McDonald

Sangam 19 - PLSQL still the coolest
Sangam 19 - PLSQL still the coolestSangam 19 - PLSQL still the coolest
Sangam 19 - PLSQL still the coolestConnor McDonald
 
UKOUG - 25 years of hints and tips
UKOUG - 25 years of hints and tipsUKOUG - 25 years of hints and tips
UKOUG - 25 years of hints and tipsConnor McDonald
 
Sangam 19 - Successful Applications on Autonomous
Sangam 19 - Successful Applications on AutonomousSangam 19 - Successful Applications on Autonomous
Sangam 19 - Successful Applications on AutonomousConnor McDonald
 
APEX tour 2019 - successful development with autonomous
APEX tour 2019 - successful development with autonomousAPEX tour 2019 - successful development with autonomous
APEX tour 2019 - successful development with autonomousConnor McDonald
 
APAC Groundbreakers 2019 - Perth/Melbourne
APAC Groundbreakers 2019 - Perth/Melbourne APAC Groundbreakers 2019 - Perth/Melbourne
APAC Groundbreakers 2019 - Perth/Melbourne Connor McDonald
 
OOW19 - Flashback, not just for DBAs
OOW19 - Flashback, not just for DBAsOOW19 - Flashback, not just for DBAs
OOW19 - Flashback, not just for DBAsConnor McDonald
 
OOW19 - Read consistency
OOW19 - Read consistencyOOW19 - Read consistency
OOW19 - Read consistencyConnor McDonald
 
OOW19 - Slower and less secure applications
OOW19 - Slower and less secure applicationsOOW19 - Slower and less secure applications
OOW19 - Slower and less secure applicationsConnor McDonald
 
OOW19 - Killing database sessions
OOW19 - Killing database sessionsOOW19 - Killing database sessions
OOW19 - Killing database sessionsConnor McDonald
 
Latin America Tour 2019 - 18c and 19c featues
Latin America Tour 2019   - 18c and 19c featuesLatin America Tour 2019   - 18c and 19c featues
Latin America Tour 2019 - 18c and 19c featuesConnor McDonald
 
Latin America tour 2019 - Flashback
Latin America tour 2019 -  FlashbackLatin America tour 2019 -  Flashback
Latin America tour 2019 - FlashbackConnor McDonald
 
Latin America Tour 2019 - slow data and sql processing
Latin America Tour 2019  - slow data and sql processingLatin America Tour 2019  - slow data and sql processing
Latin America Tour 2019 - slow data and sql processingConnor McDonald
 
OG Yatra - upgrading to the new 12c+ optimizer
OG Yatra - upgrading to the new 12c+ optimizerOG Yatra - upgrading to the new 12c+ optimizer
OG Yatra - upgrading to the new 12c+ optimizerConnor McDonald
 
OG Yatra - 25 years of hints and tips
OG Yatra - 25 years of hints and tipsOG Yatra - 25 years of hints and tips
OG Yatra - 25 years of hints and tipsConnor McDonald
 
OG Yatra - Flashback, not just for developers
OG Yatra - Flashback, not just for developersOG Yatra - Flashback, not just for developers
OG Yatra - Flashback, not just for developersConnor McDonald
 
Kscope19 - Flashback: Good for Developers as well as DBAs
Kscope19 - Flashback: Good for Developers as well as DBAsKscope19 - Flashback: Good for Developers as well as DBAs
Kscope19 - Flashback: Good for Developers as well as DBAsConnor McDonald
 
Kscope19 - Understanding the basics of SQL processing
Kscope19 - Understanding the basics of SQL processingKscope19 - Understanding the basics of SQL processing
Kscope19 - Understanding the basics of SQL processingConnor McDonald
 
APEX Connect 2019 - SQL Tuning 101
APEX Connect 2019 - SQL Tuning 101APEX Connect 2019 - SQL Tuning 101
APEX Connect 2019 - SQL Tuning 101Connor McDonald
 

More from Connor McDonald (20)

Flashback ITOUG
Flashback ITOUGFlashback ITOUG
Flashback ITOUG
 
Sangam 19 - PLSQL still the coolest
Sangam 19 - PLSQL still the coolestSangam 19 - PLSQL still the coolest
Sangam 19 - PLSQL still the coolest
 
UKOUG - 25 years of hints and tips
UKOUG - 25 years of hints and tipsUKOUG - 25 years of hints and tips
UKOUG - 25 years of hints and tips
 
Sangam 19 - Successful Applications on Autonomous
Sangam 19 - Successful Applications on AutonomousSangam 19 - Successful Applications on Autonomous
Sangam 19 - Successful Applications on Autonomous
 
APEX tour 2019 - successful development with autonomous
APEX tour 2019 - successful development with autonomousAPEX tour 2019 - successful development with autonomous
APEX tour 2019 - successful development with autonomous
 
APAC Groundbreakers 2019 - Perth/Melbourne
APAC Groundbreakers 2019 - Perth/Melbourne APAC Groundbreakers 2019 - Perth/Melbourne
APAC Groundbreakers 2019 - Perth/Melbourne
 
OOW19 - Flashback, not just for DBAs
OOW19 - Flashback, not just for DBAsOOW19 - Flashback, not just for DBAs
OOW19 - Flashback, not just for DBAs
 
OOW19 - Read consistency
OOW19 - Read consistencyOOW19 - Read consistency
OOW19 - Read consistency
 
OOW19 - Slower and less secure applications
OOW19 - Slower and less secure applicationsOOW19 - Slower and less secure applications
OOW19 - Slower and less secure applications
 
OOW19 - Killing database sessions
OOW19 - Killing database sessionsOOW19 - Killing database sessions
OOW19 - Killing database sessions
 
Latin America Tour 2019 - 18c and 19c featues
Latin America Tour 2019   - 18c and 19c featuesLatin America Tour 2019   - 18c and 19c featues
Latin America Tour 2019 - 18c and 19c featues
 
Latin America tour 2019 - Flashback
Latin America tour 2019 -  FlashbackLatin America tour 2019 -  Flashback
Latin America tour 2019 - Flashback
 
Latin America Tour 2019 - slow data and sql processing
Latin America Tour 2019  - slow data and sql processingLatin America Tour 2019  - slow data and sql processing
Latin America Tour 2019 - slow data and sql processing
 
ANSI vs Oracle language
ANSI vs Oracle languageANSI vs Oracle language
ANSI vs Oracle language
 
OG Yatra - upgrading to the new 12c+ optimizer
OG Yatra - upgrading to the new 12c+ optimizerOG Yatra - upgrading to the new 12c+ optimizer
OG Yatra - upgrading to the new 12c+ optimizer
 
OG Yatra - 25 years of hints and tips
OG Yatra - 25 years of hints and tipsOG Yatra - 25 years of hints and tips
OG Yatra - 25 years of hints and tips
 
OG Yatra - Flashback, not just for developers
OG Yatra - Flashback, not just for developersOG Yatra - Flashback, not just for developers
OG Yatra - Flashback, not just for developers
 
Kscope19 - Flashback: Good for Developers as well as DBAs
Kscope19 - Flashback: Good for Developers as well as DBAsKscope19 - Flashback: Good for Developers as well as DBAs
Kscope19 - Flashback: Good for Developers as well as DBAs
 
Kscope19 - Understanding the basics of SQL processing
Kscope19 - Understanding the basics of SQL processingKscope19 - Understanding the basics of SQL processing
Kscope19 - Understanding the basics of SQL processing
 
APEX Connect 2019 - SQL Tuning 101
APEX Connect 2019 - SQL Tuning 101APEX Connect 2019 - SQL Tuning 101
APEX Connect 2019 - SQL Tuning 101
 

Recently uploaded

"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...Fwdays
 
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)Wonjun Hwang
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Patryk Bandurski
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsRizwan Syed
 
Pigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food ManufacturingPigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food ManufacturingPigging Solutions
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024Lorenzo Miniero
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...shyamraj55
 
My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024The Digital Insurer
 
Unblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesUnblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesSinan KOZAK
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticscarlostorres15106
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Mattias Andersson
 
SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024Scott Keck-Warren
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebUiPathCommunity
 
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr LapshynFwdays
 
Transcript: New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024BookNet Canada
 
Vertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsVertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsMiki Katsuragi
 
Bluetooth Controlled Car with Arduino.pdf
Bluetooth Controlled Car with Arduino.pdfBluetooth Controlled Car with Arduino.pdf
Bluetooth Controlled Car with Arduino.pdfngoud9212
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Scott Keck-Warren
 
costume and set research powerpoint presentation
costume and set research powerpoint presentationcostume and set research powerpoint presentation
costume and set research powerpoint presentationphoebematthew05
 

Recently uploaded (20)

"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks..."LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
"LLMs for Python Engineers: Advanced Data Analysis and Semantic Kernel",Oleks...
 
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
Bun (KitWorks Team Study 노별마루 발표 2024.4.22)
 
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
Integration and Automation in Practice: CI/CD in Mule Integration and Automat...
 
Scanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL CertsScanning the Internet for External Cloud Exposures via SSL Certs
Scanning the Internet for External Cloud Exposures via SSL Certs
 
Pigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food ManufacturingPigging Solutions in Pet Food Manufacturing
Pigging Solutions in Pet Food Manufacturing
 
SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024SIP trunking in Janus @ Kamailio World 2024
SIP trunking in Janus @ Kamailio World 2024
 
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
Automating Business Process via MuleSoft Composer | Bangalore MuleSoft Meetup...
 
My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024My INSURER PTE LTD - Insurtech Innovation Award 2024
My INSURER PTE LTD - Insurtech Innovation Award 2024
 
Unblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen FramesUnblocking The Main Thread Solving ANRs and Frozen Frames
Unblocking The Main Thread Solving ANRs and Frozen Frames
 
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmaticsKotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
Kotlin Multiplatform & Compose Multiplatform - Starter kit for pragmatics
 
Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?Are Multi-Cloud and Serverless Good or Bad?
Are Multi-Cloud and Serverless Good or Bad?
 
SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024SQL Database Design For Developers at php[tek] 2024
SQL Database Design For Developers at php[tek] 2024
 
Vulnerability_Management_GRC_by Sohang Sengupta.pptx
Vulnerability_Management_GRC_by Sohang Sengupta.pptxVulnerability_Management_GRC_by Sohang Sengupta.pptx
Vulnerability_Management_GRC_by Sohang Sengupta.pptx
 
Dev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio WebDev Dives: Streamline document processing with UiPath Studio Web
Dev Dives: Streamline document processing with UiPath Studio Web
 
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
"Federated learning: out of reach no matter how close",Oleksandr Lapshyn
 
Transcript: New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024Transcript: New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024
Transcript: New from BookNet Canada for 2024: BNC BiblioShare - Tech Forum 2024
 
Vertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering TipsVertex AI Gemini Prompt Engineering Tips
Vertex AI Gemini Prompt Engineering Tips
 
Bluetooth Controlled Car with Arduino.pdf
Bluetooth Controlled Car with Arduino.pdfBluetooth Controlled Car with Arduino.pdf
Bluetooth Controlled Car with Arduino.pdf
 
Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024Advanced Test Driven-Development @ php[tek] 2024
Advanced Test Driven-Development @ php[tek] 2024
 
costume and set research powerpoint presentation
costume and set research powerpoint presentationcostume and set research powerpoint presentation
costume and set research powerpoint presentation
 

Wellington APAC Groundbreakers tour - SQL Pattern Matching

  • 1.
  • 2. Copyright © 2018, Oracle and/or its affiliates. All rights reserved. Connor McDonald
  • 3. Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 3
  • 4. Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 4
  • 5. Copyright © 2018, Oracle and/or its affiliates. All rights reserved. | Stuff youtube bit.ly/youtube-connor blog bit.ly/blog-connor twitter bit.ly/twitter-connor 400+ posts mainly on database & development 250 technical videos, new uploads every week rants and raves on tech and the world :-)
  • 6. Copyright © 2018, Oracle and/or its affiliates. All rights reserved. etc... facebook bit.ly/facebook-connor linkedin bit.ly/linkedin-connor instagram bit.ly/instagram-connor slideshare bit.ly/slideshare-connor
  • 7. Copyright © 2018, Oracle and/or its affiliates. All rights reserved. 7https://asktom.oracle.com
  • 8. Copyright © 2018, Oracle and/or its affiliates. All rights reserved. https://asktom.oracle.com/officehours
  • 9. Copyright © 2017, Oracle and/or its affiliates. All rights reserved. 150 hours free access so far 9
  • 10. Pattern Matching in 12c SQL Connor McDonald Developer Advocate
  • 11. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | before we start 11
  • 12. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | key point 12
  • 13. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | this session is about 13
  • 14. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | smart not smart ass 14
  • 15. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL can do anything 15
  • 16. SQL> with x( s, ind ) as 2 ( select sud, instr( sud, '.' ) 3 from ( select replace(replace( 4 replace(replace(:board,'-'),'|'),' '),chr(10)) sud 5 from dual ) 6 union all 7 select substr(s,1,ind-1)||z||substr(s,ind+1) 8 , instr(s,'.',ind+1) 9 from x 10 , ( select to_char( rownum ) z 11 from dual connect by rownum <= 9 ) z 12 where ind > 0 13 and not exists ( 14 select null 15 from ( select rownum lp from dual 16 connect by rownum <= 9 ) 17 where z = substr(s,trunc((ind-1)/9)*9+lp,1) 16
  • 17. 18 or z = substr(s,mod(ind-1,9)-8+lp*9,1) 19 or z = substr(s,mod(trunc((ind-1)/3),3)*3 20 +trunc((ind-1)/27)*27+lp 21 +trunc((lp-1)/3)*6,1) 22 ) 23 ), 24 result as ( 25 select s 26 from x 27 where ind = 0 ) 28 select 29 regexp_replace(substr(s,(idx-1)*9+1,9), 30 '(...)(...)(...)', 31 '1|2|3')|| 32 case when mod(idx,3)=0 then chr(10)||rpad('-',11,'-') end soln 33 from result, 34 ( select level idx 35 from dual 36 connect by level <= 9 ) 17 Ack: Anton Scheffer, https://technology.amis.nl
  • 18. SQL> variable board varchar2(1000) SQL> begin :board := 2 '53.|.7.|... 3 6..|195|... 4 .98|...|.6. 5 ----------- 6 8..|.61|..3 7 4..|8.3|..1 8 7..|.2.|..6 9 ----------- 10 .6.|...|28. 11 ...|419|..5 12 ...|.8.|.79 13 '; 14 end; 18 5 3 7 6 1 9 5 9 8 6 8 6 1 3 4 8 3 1 7 2 6 6 2 8 4 1 9 5 8 7 9
  • 20. 20 100% % of developers that will need to solve Sudoku as part of their job
  • 21. 21 100% % of developers that need to get real sh#@t done
  • 22. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | real stuff 22
  • 23. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | classical problem 23
  • 24. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select deptno, ename 2 from emp 3 order by 1,2; DEPTNO ENAME ---------- ---------- 10 CLARK 10 KING 10 MILLER 20 ADAMS 20 FORD 20 JONES 20 SCOTT 20 SMITH 30 ALLEN 30 BLAKE 30 JAMES 30 MARTIN 30 TURNER 30 WARD 24
  • 25. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | DEPTNO MEMBERS ---------- ------------------------------------- 10 CLARK,KING,MILLER 20 SMITH,JONES,SCOTT,ADAMS,FORD 30 ALLEN,WARD,MARTIN,BLAKE,TURNER,JAMES 25
  • 26. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | how we used to do it 26
  • 27. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select deptno , rtrim(ename,',') enames 2 from ( select deptno,ename,rn 3 from emp 4 model 5 partition by (deptno) 6 dimension by ( 7 row_number() over 8 (partition by deptno order by ename) rn 9 ) 10 measures (cast(ename as varchar2(40)) ename) 11 rules 12 ( ename[any] 13 order by rn desc = ename[cv()]||','||ename[cv()+1]) 14 ) 15 where rn = 1 16 order by deptno; DEPTNO ENAMES ---------- ---------------------------------------- 10 CLARK,KING,MILLER 20 ADAMS,FORD,JONES,SCOTT,SMITH 30 ALLEN,BLAKE,JAMES,MARTIN,TURNER,WARD 27
  • 28. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select deptno, 2 substr(max(sys_connect_by_path(ename, ',')), 2) members 3 from (select deptno, ename, 4 row_number () 5 over (partition by deptno order by empno) rn 6 from emp) 7 start with rn = 1 8 connect by prior rn = rn - 1 9 and prior deptno = deptno 10 group by deptno 11 / DEPTNO MEMBERS ---------- --------------------------------------------------------- 30 ALLEN,WARD,MARTIN,BLAKE,TURNER,JAMES 20 SMITH,JONES,SCOTT,ADAMS,FORD 10 CLARK,KING,MILLER 28
  • 29. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select deptno, 2 xmltransform 3 ( sys_xmlagg 4 ( sys_xmlgen(ename) 5 ), 6 xmltype 7 ( 8 '<?xml version="1.0"?><xsl:stylesheet version="1.0" 9 xmlns:xsl="http://www.w3.org/1999/XSL/Transform"> 10 <xsl:template match="/"> 11 <xsl:for-each select="/ROWSET/ENAME"> 12 <xsl:value-of select="text()"/>,</xsl:for-each> 13 </xsl:template> 14 </xsl:stylesheet>' 15 ) 16 ).getstringval() members 17 from emp 18 group by deptno; DEPTNO MEMBERS ---------- -------------------------------------------------------- 10 CLARK,MILLER,KING, 20 SMITH,FORD,ADAMS,SCOTT,JONES, 30 ALLEN,JAMES,TURNER,BLAKE,MARTIN,WARD, 29
  • 30. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> create or replace type string_agg_type as object 2 ( 3 total varchar2(4000), 4 5 static function 6 ODCIAggregateInitialize(sctx IN OUT string_agg_type ) 7 return number, 8 9 member function 10 ODCIAggregateIterate(self IN OUT string_agg_type , 11 value IN varchar2 ) 12 return number, 13 14 member function 15 ODCIAggregateTerminate(self IN string_agg_type, 16 returnValue OUT varchar2, 17 flags IN number) 18 return number, 19 20 member function 21 ODCIAggregateMerge(self IN OUT string_agg_type, 22 ctx2 IN string_agg_type) 23 return number 24 ); 25 / 30
  • 31. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | 11g 31
  • 32. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select deptno, 2 listagg( ename, ',') 3 within group (order by empno) members 4 from emp 5 group by deptno; DEPTNO MEMBERS ---------- ----------------------------------------- 10 CLARK,KING,MILLER 20 SMITH,JONES,SCOTT,ADAMS,FORD 30 ALLEN,WARD,MARTIN,BLAKE,TURNER,JAMES 32
  • 33. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | question solution 33
  • 34. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | still challenges 34
  • 35. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | example 35
  • 36. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | 36
  • 37. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | 37
  • 38. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | "I want to reward active customers… If their transaction volume grows by 20% in a day, or grows by 10% for 3 consecutive days, then show me their details" 38
  • 39. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select * from cust_summary 2 order by 1,2; CUSTOMER DTE TXN_CNT ------------------------------ --------- ---------- Gerald Jones 06-FEB-17 100 Gerald Jones 07-FEB-17 130 Gerald Jones 08-FEB-17 145 Gerald Jones 09-FEB-17 200 Gerald Jones 10-FEB-17 225 Gerald Jones 11-FEB-17 255 Gerald Jones 12-FEB-17 285 Gerald Jones 13-FEB-17 315 John Smith 01-FEB-17 100 John Smith 02-FEB-17 103 John Smith 03-FEB-17 116 John Smith 04-FEB-17 129 John Smith 05-FEB-17 142 Sue Brown 06-FEB-17 50 Sue Brown 07-FEB-17 53 Sue Brown 08-FEB-17 72 ... 39
  • 40. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | 40
  • 41. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | analytics 41
  • 42. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | "I want to reward active customers… If their transaction volume grows by 20% in a day, or grows by 10% for 3 consecutive days, then show me the details" 42
  • 43. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select customer, dte, cumu_txns, next_txn, next_txn - cumu_txns daily_txn 2 from ( 3 select customer, dte, cumu_txns 4 , lead(cumu_txns) over ( 5 partition by customer order by dte 6 ) next_txn 7 from cust_summary 8 ); CUSTOMER DTE CUMU_TXNS NEXT_TXN DAILY_TXN ------------------------------ --------- ---------- ---------- ---------- Gerald Jones 06-FEB-17 100 130 30 Gerald Jones 07-FEB-17 130 145 15 Gerald Jones 08-FEB-17 145 200 55 Gerald Jones 09-FEB-17 200 225 25 Gerald Jones 10-FEB-17 225 255 30 43
  • 44. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | "I want to reward active customers… If their transaction volume grows by 20% in a day, or grows by 10% for 3 consecutive days, then show me the details" 44
  • 45. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select customer, dte, cumu_txns, next_txn, next_txn - cumu_txns daily_txn 2 , case 3 when next_txn >= cumu_txns * 1.20 then 'FAST' 4 when next_txn >= cumu_txns * 1.10 then 'SLOW' 5 end growth_class 6 from ( 7 select customer, dte, cumu_txns 8 , lead(cumu_txns) over ( 9 partition by customer order by dte 10 ) next_txn 11 from cust_summary 12 ); CUSTOMER DTE CUMU_TXNS NEXT_TXN DAILY_TXN GROWTH_CLASS ------------------------------ --------- ---------- ---------- ---------- ------------ Gerald Jones 06-FEB-17 100 130 30 FAST Gerald Jones 07-FEB-17 130 145 15 SLOW Gerald Jones 08-FEB-17 145 200 55 FAST Gerald Jones 09-FEB-17 200 225 25 SLOW Gerald Jones 10-FEB-17 225 255 30 SLOW Gerald Jones 11-FEB-17 255 285 30 SLOW Gerald Jones 12-FEB-17 285 315 30 SLOW 45
  • 46. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | "I want to reward active customers… If their transaction volume grows by 20% in a day, or grows by 10% for 3 consecutive days, then show me the details" 46
  • 47. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select customer, growth_class, dte, cumu_txns, next_txn, daily_txn 2 , case 3 when growth_class is not null and 4 ( lag(growth_class) over ( 5 partition by customer order by dte 6 ) is null 7 or 8 lag(growth_class) over ( 9 partition by customer order by dte 10 ) != growth_class 11 ) 12 then dte 13 end growthstartdate 14 from ( 15 select customer, dte, cumu_txns, next_txn, next_txn - cumu_txns daily_txn 16 , case 17 when next_txn >= cumu_txns * 1.20 then 'FAST' 18 when next_txn >= cumu_txns * 1.10 then 'SLOW' 19 end growth_class 20 from ( 21 select customer, dte, cumu_txns 22 , lead(cumu_txns) over ( 23 partition by customer order by dte 24 ) next_txn 25 from cust_summary 26 ) ) 47
  • 48. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select customer, growth_class, dte, cumu_txns, next_txn, daily_txn 2 , last_value(growthstartdate ignore nulls) over ( 3 partition by customer, growth_class order by dte 4 rows between unbounded preceding and current row 5 ) startdate 6 from ( 7 select customer, growth_class, dte, cumu_txns, next_txn, daily_txn 8 , case 9 when growth_class is not null and 10 ( lag(growth_class) over ( 11 partition by customer order by dte ) is null or 12 lag(growth_class) over ( 13 partition by customer order by dte 14 ) != growth_class ) 15 then dte 16 end growthstartdate 17 from ( 18 select customer, dte, cumu_txns, next_txn, next_txn - cumu_txns daily_txn 19 , case when next_txn >= cumu_txns * 1.20 then 'FAST' 20 when next_txn >= cumu_txns * 1.10 then 'SLOW' 21 end growth_class 22 from ( 23 select customer, dte, cumu_txns 24 , lead(cumu_txns) over (partition by customer order by dte 25 ) next_txn 26 from cust_summary 27 ) ) ) 28 where growth_class is not null 48
  • 49. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select customer, growth_class, startdate 2 , min(cumu_txns) keep (dense_rank first order by dte) start_txn 3 , max(dte) enddate 4 , max(next_txn) keep (dense_rank last order by dte) end_txn 5 , avg(daily_txn) avg_daily_txn 6 from ( 7 select customer, growth_class, dte, cumu_txns, next_txn, daily_txn 8 , last_value(growthstartdate ignore nulls) over ( 9 partition by customer, growth_class order by dte 10 rows between unbounded preceding and current row 11 ) startdate 12 from ( 13 select customer, growth_class, dte, cumu_txns, next_txn, daily_txn 14 , case when growth_class is not null and 15 ( lag(growth_class) over (partition by customer order by dte) is null or 16 lag(growth_class) over (partition by customer order by dte) != growth_class ) 17 then dte end growthstartdate 18 from ( 19 select customer, dte, cumu_txns, next_txn, next_txn - cumu_txns daily_txn 20 , case 21 when next_txn >= cumu_txns * 1.20 then 'FAST' 22 when next_txn >= cumu_txns * 1.10 then 'SLOW' 23 end growth_class 24 from ( 25 select customer, dte, cumu_txns 26 , lead(cumu_txns) over ( 27 partition by customer order by dte 28 ) next_txn 29 from cust_summary 30 ) ) ) 31 where growth_class is not null ) 32 group by customer, growth_class, startdate 33 having count(*) >= case growth_class when 'FAST' then 1 when 'SLOW' then 3 end 34 order by customer, startdate; 49
  • 50. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | CUSTOMER GROWTH_CLASS STARTDATE START_TXN ENDDATE END_TXN AVG_DAILY_TXN ------------------- ---------------- --------- ---------- --------- ---------- ------------- Gerald Jones FAST 06-FEB-17 100 06-FEB-17 130 30 Gerald Jones FAST 08-FEB-17 145 08-FEB-17 200 55 Gerald Jones SLOW 09-FEB-17 200 12-FEB-17 315 28.75 John Smith SLOW 02-FEB-17 103 05-FEB-17 160 14.25 John Smith FAST 07-FEB-17 165 07-FEB-17 210 45 Sue Brown FAST 07-FEB-17 53 08-FEB-17 97 22 50
  • 51. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | "easy!" 51
  • 52. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | 52 W T H
  • 53. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | analytics are about computation 53
  • 54. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | users look for patterns 54
  • 55. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | question solution 55
  • 56. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | need a syntax ... 56
  • 57. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | ... to describe patterns 57
  • 58. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select customer, growth_class, startdate, start_txn, enddate, 2 end_txn, avg_daily_txn 3 from cust_summary 4 match_recognize ( 5 partition by customer order by dte 6 measures 7 classifier() as growth_class 8 , first(dte) as startdate 9 , first(cumu_txns) as start_txn 10 , last(dte) as enddate 11 , next(cumu_txns) as end_txn 12 , (next(cumu_txns) - first(cumu_txns)) / count(*) as avg_daily_txn 13 one row per match after match skip past last row 14 pattern ( fast+ | slow{3,} ) 15 define fast as next(cumu_txns) / cumu_txns >= 1.20 16 , slow as next(slow.cumu_txns) / slow.cumu_txns >= 1.10 and 17 next(slow.cumu_txns) / slow.cumu_txns < 1.20 18 ) 19 order by customer, startdate; 58 regular expression
  • 59. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | CUSTOMER GROWTH_CLASS STARTDATE START_TXN ENDDATE END_TXN AVG_DAILY_TXN ------------------ --------------- --------- ---------- --------- ---------- ------------- Gerald Jones FAST 06-FEB-17 100 06-FEB-17 130 30 Gerald Jones FAST 08-FEB-17 145 08-FEB-17 200 55 Gerald Jones SLOW 09-FEB-17 200 12-FEB-17 315 28.75 John Smith SLOW 02-FEB-17 103 05-FEB-17 160 14.25 John Smith FAST 07-FEB-17 165 07-FEB-17 210 45 Sue Brown FAST 07-FEB-17 53 08-FEB-17 97 22 59 3+ consecutive days, but show one row
  • 60. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select customer, growth_class, startdate, start_txn, enddate, 2 end_txn, avg_daily_txn 3 from cust_summary 4 match_recognize ( 5 partition by customer order by dte 6 measures 7 classifier() as growth_class 8 , first(dte) as startdate 9 , first(cumu_txns) as start_txn 10 , last(dte) as enddate 11 , next(cumu_txns) as end_txn 12 , (next(cumu_txns) - first(cumu_txns)) / count(*) as avg_daily_txn 13 one row per match after match skip past last row 14 pattern ( fast+ | slow{3,} ) 15 define fast as next(cumu_txns) / cumu_txns >= 1.20 16 , slow as next(slow.cumu_txns) / slow.cumu_txns >= 1.10 and 17 next(slow.cumu_txns) / slow.cumu_txns < 1.20 18 ) 19 order by customer, startdate; 60
  • 61. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | done ! 61
  • 62. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | w t f 62
  • 63. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | "chapter 1" 63
  • 64. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | "Hello World" pattern match 64
  • 65. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select * from t; X ---------- 1 2 3 5 6 9 10 11 16 17 19 21 30 65 find contiguous numbers LO HI ---------- ---------- 1 3 5 6 9 11 16 17 19 19 21 21 30 30
  • 66. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select * 2 from t 3 match_recognize ( 4 order by x 5 all rows per match 6 pattern ( contig* ) 7 define contig as x = prev(x) + 1 8 ); 66
  • 67. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select * 2 from t 3 match_recognize ( 4 order by x 5 all rows per match 6 pattern ( contig* ) 7 define contig as x = prev(x) + 1 8 ); X ---------- 1 2 3 5 6 9 10 11 16 17 19 21 30 67
  • 68. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | 68
  • 69. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select * 2 from t 3 match_recognize ( 4 order by x 5 all rows per match 6 pattern ( contig+ ) 7 define contig as x = prev(x) + 1 8 ); X ---------- 2 3 6 10 11 17 69 1 2 3 5 6 9 10 11 16 1719 21 30
  • 70. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select * 2 from t 3 match_recognize ( 4 order by x 5 all rows per match 6 pattern ( any_old_row contig* ) 7 define 8 contig as x = prev(x) + 1, 9 any_old_row as 1=1 10 ); 70 "every row is the potentially the start of a contiguous sequence…"
  • 71. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select * 2 from t 3 match_recognize ( 4 order by x 5 all rows per match 6 pattern ( any_old_row contig* ) 7 define 8 contig as x = prev(x) + 1, 9 any_old_row as 1=1 10 ); 71 "... followed by zero or more contiguous values" "every row is the potentially the start of a contiguous sequence…"
  • 72. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select * 2 from t 3 match_recognize ( 4 order by x 5 all rows per match 6 pattern ( any_old_row contig* ) 7 define 8 contig as x = prev(x) + 1, 9 any_old_row as 1=1 10 ); 72 X ---------- 1 2 3 5 6 9 10 11 16 17 19 21 30
  • 73. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select * 2 from t 3 match_recognize ( 4 order by x 5 all rows per match 6 pattern ( any_old_row contig* ) 7 define contig as x = prev(x) + 1 ); X ---------- 1 2 3 5 6 9 10 11 16 17 19 21 30 73
  • 74. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | "um…er…. that's just all the rows isn't it ?" 74
  • 75. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | measures 75 what we want to see
  • 76. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select * from t 2 match_recognize ( order by x 3 measures 4 first(x) lo 5 , last(x) hi 6 all rows per match 7 pattern ( any_old_row contig* ) 8 define contig as x = prev(x) + 1 ); X LO HI ---------- ---------- ---------- 1 1 1 2 1 2 3 1 3 5 5 5 6 5 6 9 9 9 10 9 10 11 9 11 16 16 16 17 16 17 19 19 19 21 21 21 30 30 30 76
  • 77. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | "I only want THOSE rows …" 77
  • 78. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | "…I do not want ALL of the rows …" 78
  • 79. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select * from t 2 match_recognize ( order by x 3 measures 4 first(x) lo 5 , last(x) hi 6 one row per match 7 pattern ( any_old_row contig* ) 8 define contig as x = prev(x) + 1 ); LO HI ---------- ---------- 1 3 5 6 9 11 16 17 19 19 21 21 30 30 79
  • 80. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select * from t 2 match_recognize ( order by x 3 measures 4 first(x) lo 5 , last(x) hi 6 , count(*) range 7 pattern ( any_old_row contig* ) 8 define contig as x = prev(x) + 1 ); LO HI RANGE ---------- ---------- ---------- 1 3 3 5 6 2 9 11 3 16 17 2 19 19 1 21 21 1 30 30 1 80 one row per match = default
  • 81. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | "that is not a normal COUNT(*)" 81
  • 82. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | keywords 82
  • 83. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select * from t 2 match_recognize ( order by x 3 measures 4 x x 5 , first(x) lo 6 , last(x) hi 7 , prev(x) prv 8 , next(x) nxt 9 , count(*) range 10 , final last(x) fin 11 , contig.x as contig_x 12 , count(contig.*) contig_count 13 pattern ( any_old_row contig* ) 14 define contig as x = prev(x) + 1 15 ); X LO HI PRV NXT RANGE FIN CONTIG_X CONTIG_COUNT ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ------------ 3 1 3 2 5 3 3 3 2 6 5 6 5 9 2 6 6 1 11 9 11 10 16 3 11 11 2 17 16 17 16 19 2 17 17 1 19 19 19 17 21 1 19 0 21 21 21 19 30 1 21 0 30 30 30 21 1 30 0 83 include the column / expression
  • 84. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select * from t 2 match_recognize ( order by x 3 measures 4 x x 5 , first(x) lo 6 , last(x) hi 7 , prev(x) prv 8 , next(x) nxt 9 , count(*) range 10 , final last(x) fin 11 , contig.x as contig_x 12 , count(contig.*) contig_count 13 pattern ( any_old_row contig* ) 14 define contig as x = prev(x) + 1 15 ); X LO HI PRV NXT RANGE FIN CONTIG_X CONTIG_COUNT ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ------------ 3 1 3 2 5 3 3 3 2 6 5 6 5 9 2 6 6 1 11 9 11 10 16 3 11 11 2 17 16 17 16 19 2 17 17 1 19 19 19 17 21 1 19 0 21 21 21 19 30 1 21 0 30 30 30 21 1 30 0 84 value from first row in match
  • 85. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select * from t 2 match_recognize ( order by x 3 measures 4 x x 5 , first(x) lo 6 , last(x) hi 7 , prev(x) prv 8 , next(x) nxt 9 , count(*) range 10 , final last(x) fin 11 , contig.x as contig_x 12 , count(contig.*) contig_count 13 pattern ( any_old_row contig* ) 14 define contig as x = prev(x) + 1 15 ); X LO HI PRV NXT RANGE FIN CONTIG_X CONTIG_COUNT ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ------------ 3 1 3 2 5 3 3 3 2 6 5 6 5 9 2 6 6 1 11 9 11 10 16 3 11 11 2 17 16 17 16 19 2 17 17 1 19 19 19 17 21 1 19 0 21 21 21 19 30 1 21 0 30 30 30 21 1 30 0 85 value from last row in match
  • 86. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select * from t 2 match_recognize ( order by x 3 measures 4 x x 5 , first(x) lo 6 , last(x) hi 7 , prev(x) prv 8 , next(x) nxt 9 , count(*) range 10 , final last(x) fin 11 , contig.x as contig_x 12 , count(contig.*) contig_count 13 pattern ( any_old_row contig* ) 14 define contig as x = prev(x) + 1 15 ); X LO HI PRV NXT RANGE FIN CONTIG_X CONTIG_COUNT ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ------------ 3 1 3 2 5 3 3 3 2 6 5 6 5 9 2 6 6 1 11 9 11 10 16 3 11 11 2 17 16 17 16 19 2 17 17 1 19 19 19 17 21 1 19 0 21 21 21 19 30 1 21 0 30 30 30 21 1 30 0 86 value from previous referred row
  • 87. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select * from t 2 match_recognize ( order by x 3 measures 4 x x 5 , first(x) lo 6 , last(x) hi 7 , prev(x) prv 8 , next(x) nxt 9 , count(*) range 10 , final last(x) fin 11 , contig.x as contig_x 12 , count(contig.*) contig_count 13 pattern ( any_old_row contig* ) 14 define contig as x = prev(x) + 1 15 ); X LO HI PRV NXT RANGE FIN CONTIG_X CONTIG_COUNT ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ------------ 3 1 3 2 5 3 3 3 2 6 5 6 5 9 2 6 6 1 11 9 11 10 16 3 11 11 2 17 16 17 16 19 2 17 17 1 19 19 19 17 21 1 19 0 21 21 21 19 30 1 21 0 30 30 30 21 1 30 0 87 value from next referred row
  • 88. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select * from t 2 match_recognize ( order by x 3 measures 4 x x 5 , first(x) lo 6 , last(x) hi 7 , prev(x) prv 8 , next(x) nxt 9 , count(*) range 10 , final last(x) fin 11 , contig.x as contig_x 12 , count(contig.*) contig_count 13 pattern ( any_old_row contig* ) 14 define contig as x = prev(x) + 1 15 ); X LO HI PRV NXT RANGE FIN CONTIG_X CONTIG_COUNT ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ------------ 3 1 3 2 5 3 3 3 2 6 5 6 5 9 2 6 6 1 11 9 11 10 16 3 11 11 2 17 16 17 16 19 2 17 17 1 19 19 19 17 21 1 19 0 21 21 21 19 30 1 21 0 30 30 30 21 1 30 0 88 count of rows in the match
  • 89. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select * from t 2 match_recognize ( order by x 3 measures 4 x x 5 , first(x) lo 6 , last(x) hi 7 , prev(x) prv 8 , next(x) nxt 9 , count(*) range 10 , final last(x) fin 11 , contig.x as contig_x 12 , count(contig.*) contig_count 13 pattern ( any_old_row contig* ) 14 define contig as x = prev(x) + 1 15 ); X LO HI PRV NXT RANGE FIN CONTIG_X CONTIG_COUNT ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ------------ 3 1 3 2 5 3 3 3 2 6 5 6 5 9 2 6 6 1 11 9 11 10 16 3 11 11 2 17 16 17 16 19 2 17 17 1 19 19 19 17 21 1 19 0 21 21 21 19 30 1 21 0 30 30 30 21 1 30 0 89 last row of match *
  • 90. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select * from t 2 match_recognize ( order by x 3 measures 4 x x 5 , first(x) lo 6 , last(x) hi 7 , prev(x) prv 8 , next(x) nxt 9 , count(*) range 10 , final last(x) fin 11 , contig.x as contig_x 12 , count(contig.*) contig_count 13 pattern ( any_old_row contig* ) 14 define contig as x = prev(x) + 1 15 ); X LO HI PRV NXT RANGE FIN CONTIG_X CONTIG_COUNT ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ------------ 3 1 3 2 5 3 3 3 2 6 5 6 5 9 2 6 6 1 11 9 11 10 16 3 11 11 2 17 16 17 16 19 2 17 17 1 19 19 19 17 21 1 19 0 21 21 21 19 30 1 21 0 30 30 30 21 1 30 0 90 last encountered row in 'contig'
  • 91. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select * from t 2 match_recognize ( order by x 3 measures 4 x x 5 , first(x) lo 6 , last(x) hi 7 , prev(x) prv 8 , next(x) nxt 9 , count(*) range 10 , final last(x) fin 11 , contig.x as contig_x 12 , count(contig.*) contig_count 13 pattern ( any_old_row contig* ) 14 define contig as x = prev(x) + 1 15 ); X LO HI PRV NXT RANGE FIN CONTIG_X CONTIG_COUNT ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ------------ 3 1 3 2 5 3 3 3 2 6 5 6 5 9 2 6 6 1 11 9 11 10 16 3 11 11 2 17 16 17 16 19 2 17 17 1 19 19 19 17 21 1 19 0 21 21 21 19 30 1 21 0 30 30 30 21 1 30 0 91 count of 'contig' rows
  • 92. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | but :-) 92
  • 93. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | one row per match | all rows per match 93
  • 94. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select * from t 2 match_recognize ( order by x 3 measures 4 x x 5 , first(x) lo 6 , last(x) hi 7 , prev(x) prv 8 , next(x) nxt 9 , count(*) range 10 , final last(x) fin 11 , contig.x as contig_x 12 , count(contig.*) contig_count 13 ALL ROWS PER MATCH 13 pattern ( any_old_row contig* ) 14 define contig as x = prev(x) + 1 15 ); 94 ALL ROWS PER MATCH - this row - first row of match pattern - this row - previous row from this row - next row from this row - count from first to this row - last row in the match pattern - this 'contig' row - count from first to this contig row
  • 95. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select * from t 2 match_recognize ( order by x 3 measures 4 x x 5 , first(x) lo 6 , last(x) hi 7 , prev(x) prv 8 , next(x) nxt 9 , count(*) range 10 , final last(x) fin 11 , contig.x as contig_x 12 , count(contig.*) contig_count 13 ONE ROWS PER MATCH 13 pattern ( any_old_row contig* ) 14 define contig as x = prev(x) + 1 15 ); 95 ONE ROW PER MATCH - last row of match pattern - first row of match pattern - last row of match pattern - previous row from this row - next row from this row - count of all rows in match pattern - last row in the match pattern - last 'contig' row in match pattern - count of all contig row in match pattern
  • 96. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | sounds complicated … 96
  • 97. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | .. sensible 97
  • 98. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | there's more :-) 98
  • 99. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select * from t 2 match_recognize ( order by x 3 measures 4 x x 5 , first(x) lo 6 , last(x) hi 7 , prev(x) prv 8 , next(x) nxt 9 , count(*) range 10 , final last(x) fin 11 , contig.x as contig_x 12 , count(contig.*) contig_count 13 pattern ( any_old_row contig* ) 14 define 15 contig as x = prev(x) + 1 16 ); X LO HI PRV NXT RANGE FIN CONTIG_X CONTIG_COUNT ---------- ---------- ---------- ---------- ---------- ---------- ---------- ---------- ------------ 3 1 3 2 5 3 3 3 2 6 5 6 5 9 2 6 6 1 11 9 11 10 16 3 11 11 2 17 16 17 16 19 2 17 17 1 19 19 19 17 21 1 19 0 21 21 21 19 30 1 21 0 30 30 30 21 1 30 0 99 similar expressions in DEFINE section
  • 100. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select * from t 2 match_recognize ( order by x 3 measures ... pattern ... 4 DEFINE 5 p1 as x = 1 6 , p2 as first(x) = 1 7 , p3 as last(x) = 1 8 , p4 as prev(x) = 1 9 , p5 as next(x) = 1 10 , p6 as count(*) = 1 11 , p7 as final last(x) = 1 12 , p8 as contig.x = 1 13 , p9 as count(contig.*) = 1 14 ); 100 as per ALL ROWS PER MATCH - this row - first row of match pattern - this row - previous row from this row - next row from this row - count from first to this row - ILLEGAL - this 'contig' row - count from first to this contig row
  • 101. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | review 101
  • 102. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select customer, growth_class, startdate, start_txn, enddate, 2 end_txn, avg_daily_txn 3 from cust_summary 4 match_recognize ( 5 partition by customer order by dte 6 measures 7 classifier() as growth_class 8 , first(dte) as startdate 9 , first(cumu_txns) as start_txn 10 , last(dte) as enddate 11 , next(cumu_txns) as end_txn 12 , (next(cumu_txns) - first(cumu_txns)) / count(*) as avg_daily_txn 13 one row per match after match skip past last row 14 pattern ( fast+ | slow{3,} ) 15 define fast as next(cumu_txns) / cumu_txns >= 1.20 16 , slow as next(slow.cumu_txns) / slow.cumu_txns >= 1.10 and 17 next(slow.cumu_txns) / slow.cumu_txns < 1.20 18 ) 19 order by customer, startdate; 102 SQL> select customer, growth_class, startdate, start_txn, enddate, 2 end_txn, avg_daily_txn 3 from cust_summary 4 match_recognize ( 5 partition by customer order by dte 6 measures 7 classifier() as growth_class 8 , first(dte) as startdate 9 , first(cumu_txns) as start_txn 10 , last(dte) as enddate 11 , next(cumu_txns) as end_txn 12 , (next(cumu_txns) - first(cumu_txns)) / count(*) as avg_daily_txn 13 one row per match after match skip past last row 14 pattern ( fast+ | slow{3,} ) 15 define fast as next(cumu_txns) / cumu_txns >= 1.20 16 , slow as next(slow.cumu_txns) / slow.cumu_txns >= 1.10 and 17 next(slow.cumu_txns) / slow.cumu_txns < 1.20 18 ) 19 order by customer, startdate;
  • 103. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select customer, growth_class, startdate, start_txn, enddate, 2 end_txn, avg_daily_txn 3 from cust_summary 4 match_recognize ( 5 partition by customer order by dte ... 103
  • 104. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select customer, growth_class, startdate, start_txn, enddate, 2 end_txn, avg_daily_txn 3 from cust_summary 4 match_recognize ( 5 partition by customer order by dte ... 104 logical subsets critical as per analytics
  • 105. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | patterns 105
  • 106. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | 106 SQL> select customer, growth_class, startdate, start_txn, enddate, ... 14 pattern ( fast+ | slow{3,} ) 15 define fast as next(cumu_txns) / cumu_txns >= 1.20 16 , slow as next(slow.cumu_txns) / slow.cumu_txns >= 1.10 and 17 next(slow.cumu_txns) / slow.cumu_txns < 1.20 regular expression syntax
  • 107. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | "If you have a text parsing problem, you can use regular expressions… … Now you have two problems" - anon 107
  • 108. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | * + ? {3} {3,} {3,6} {,2} ? 108 0 or more matches 1 or more matches 0 or 1 match exactly 3 matches 3 or more matches between 3 and 6 matches between 0 and 2 matches reluctance*
  • 109. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | a|b (a b){3}c permute a b c ^ $ {- a -} 109 a or b 3 times ( a then b ) then c abc,acb,bac,bca,cab,cba first row in pattern last row in pattern (^ p+ $) not a
  • 110. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | {- a -} 110 SQL> select ... 14 pattern ( {- a -} ) 15 define a = amt > 10 SQL> select ... 14 pattern ( a ) 15 define a = amt <= 10
  • 111. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | {- a -} 111 SQL> select ... measures sum(a.price) ... 14 pattern ( {- a -} ) 15 define a = amt > 10
  • 112. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | reluctance 112
  • 113. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | "Hired, Worked, Fired" 113 http://www.kibeha.dk/2015/07/row-pattern-matching-nested-within.html
  • 114. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select * from t order by 1; SEQ COL ---------- ---------- 1 Hired 2 Worked 3 Worked 4 Worked 5 Worked 6 Worked 7 Terminated 8 Hired 9 Worked 10 Worked 11 Worked 12 Worked 13 Worked 14 Terminated 15 Hired 16 Worked 17 Worked 18 Worked 19 Worked 20 Worked 21 Terminated 114
  • 115. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select * from t order by 1; SEQ COL ---------- ---------- 1 Hired 2 Worked 3 Worked 4 Worked 5 Worked 6 Worked 7 Terminated 8 Hired 9 Worked 10 Worked 11 Worked 12 Worked 13 Worked 14 Terminated 15 Hired 16 Worked 17 Worked 18 Worked 19 Worked 20 Worked 21 Terminated 115
  • 116. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select * 2 from t 3 match_recognize ( 4 order by seq 5 measures 6 first(col) as fcol, 7 col as col, 8 first(seq) p_start, 9 last(seq) p_end, 10 count(*) tot 11 one row per match 12 pattern ( hired worked* fired ) 13 define 14 hired as col = 'Hired', 15 fired as col = 'Terminated' 16 ); FCOL COL P_START P_END TOT ---------- ---------- ---------- ---------- ---------- Hired Terminated 1 21 21 116 "don't care, always true"
  • 117. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | 117
  • 118. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | greediness 118
  • 119. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select * from t order by 1; SEQ COL ---------- ---------- 1 Hired 2 Worked 3 Worked 4 Worked 5 Worked 6 Worked 7 Terminated 8 Hired 9 Worked 10 Worked 11 Worked 12 Worked 13 Worked 14 Terminated 15 Hired 16 Worked 17 Worked 18 Worked 19 Worked 20 Worked 21 Terminated 119 pattern ( hired worked* fired ) "Cool, I have my 'hired'" "Awesome, I got my 'worked' (ie, anything)" "Lets chew up rows as much as I can to see if I can find 'fired'" "Jackpot!"
  • 120. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select * 2 from t 3 match_recognize ( 4 order by seq 5 measures 6 first(col) as fcol, 7 col as col, 8 first(seq) p_start, 9 last(seq) p_end, 10 count(*) tot 11 one row per match 12 pattern ( hired worked*? fired ) 13 define 14 hired as col = 'Hired', 15 fired as col = 'Terminated' ); FCOL COL P_START P_END TOT ---------- ---------- ---------- ---------- ---------- Hired Terminated 1 7 7 Hired Terminated 8 14 7 Hired Terminated 15 21 7 120 reluctantly search
  • 121. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | be careful 121
  • 122. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select * from t order by 1; SEQ COL ---------- ---------- 1 Hired 2 Worked 3 Worked 4 Worked 5 Worked 6 Worked 7 Terminated 8 Worked 9 Worked 10 Worked 11 Worked 12 Worked 13 Worked 14 Worked 15 Worked 16 Worked 17 Worked 18 Worked 19 Worked 20 Worked 21 Worked 122
  • 123. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select * 2 from t 3 match_recognize ( 4 order by seq 5 measures 6 first(col) as fcol, 7 col as col, 8 first(seq) p_start, ... ORA-4030: Out of process memory when ... 123
  • 124. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select * 2 from t 3 match_recognize ( 4 order by seq 5 measures 6 first(col) as fcol, 7 col as col, 8 first(seq) p_start, 9 last(seq) p_end, 10 count(*) tot 11 one row per match 12 pattern ( hired worked* fired ) 13 define 14 hired as col = 'Hired', 15 worked as col = 'Worked', 15 fired as col = 'Terminated' ); 124 worked+
  • 125. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | “imagination is more important than knowledge” - Albert Einstein 125
  • 126. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | 126 examples
  • 127. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | "count of my subordinates" 127 http://www.kibeha.dk/2015/07/row-pattern-matching-nested-within.html
  • 128. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | EMPNO ENAME REPORTS --------- -------------------- ---------- 7839 KING 13 7566 JONES 4 7788 SCOTT 1 7876 ADAMS 0 7902 FORD 1 7369 SMITH 0 7698 BLAKE 5 7499 ALLEN 0 7521 WARD 0 7654 MARTIN 0 7844 TURNER 0 7900 JAMES 0 7782 CLARK 1 7934 MILLER 0 128
  • 129. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | 129 conventional style
  • 130. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select empno 2 , lpad(' ', (level-1)*2) || ename as ename 3 , ( select count(*) 4 from emp sub 5 start with sub.mgr = emp.empno 6 connect by sub.mgr = prior sub.empno 7 ) reports 8 from emp 9 start with mgr is null 10 connect by mgr = prior empno 11 order siblings by empno; EMPNO ENAME REPORTS ---------- -------------------- ---------- 7839 KING 13 7566 JONES 4 7788 SCOTT 1 7876 ADAMS 0 7902 FORD 1 ... 130 select count(*) from emp sub start with sub.mgr = emp.empno connect by sub.mgr = prior sub.empno select count(*) from emp sub start with sub.mgr = emp.empno connect by sub.mgr = prior sub.empno select count(*) from emp sub start with sub.mgr = emp.empno connect by sub.mgr = prior sub.empno select count(*) from emp sub start with sub.mgr = emp.empno connect by sub.mgr = prior sub.empno select count(*) from emp sub start with sub.mgr = emp.empno connect by sub.mgr = prior sub.empno
  • 131. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | 131 where's the pattern ? SQL> select ... 2 from cust_summary 3 match_recognize ( 4 order by ... ...
  • 132. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select lvl, empno, ename, rownum as rn 2 from ( 3 select level as lvl, empno, ename 4 from emp 5 start with mgr is null 6 connect by mgr = prior empno 7 order siblings by empno ); LVL EMPNO ENAME RN ---------- ---------- -------------------- ---------- 1 7839 KING 1 2 7566 JONES 2 3 7788 SCOTT 3 4 7876 ADAMS 4 3 7902 FORD 5 4 7369 SMITH 6 2 7698 BLAKE 7 3 7499 ALLEN 8 3 7521 WARD 9 3 7654 MARTIN 10 3 7844 TURNER 11 3 7900 JAMES 12 2 7782 CLARK 13 3 7934 MILLER 14 132 ordering sequence
  • 133. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select lvl, empno, ename, rownum as rn 2 from ( 3 select level as lvl, empno, ename 4 from emp 5 start with mgr is null 6 connect by mgr = prior empno 7 order siblings by empno ); LVL EMPNO ENAME RN ---------- ---------- -------------------- ---------- 1 7839 KING 1 2 7566 JONES 2 3 7788 SCOTT 3 4 7876 ADAMS 4 3 7902 FORD 5 4 7369 SMITH 6 2 7698 BLAKE 7 3 7499 ALLEN 8 3 7521 WARD 9 3 7654 MARTIN 10 3 7844 TURNER 11 3 7900 JAMES 12 2 7782 CLARK 13 3 7934 MILLER 14 133 "starting level"
  • 134. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select lvl, empno, ename, rownum as rn 2 from ( 3 select level as lvl, empno, ename 4 from emp 5 start with mgr is null 6 connect by mgr = prior empno 7 order siblings by empno ); LVL EMPNO ENAME RN ---------- ---------- -------------------- ---------- 1 7839 KING 1 2 7566 JONES 2 3 7788 SCOTT 3 4 7876 ADAMS 4 3 7902 FORD 5 4 7369 SMITH 6 2 7698 BLAKE 7 3 7499 ALLEN 8 3 7521 WARD 9 3 7654 MARTIN 10 3 7844 TURNER 11 3 7900 JAMES 12 2 7782 CLARK 13 3 7934 MILLER 14 134 "starting level" "next level higher then starting level?"
  • 135. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select lvl, empno, ename, rownum as rn 2 from ( 3 select level as lvl, empno, ename 4 from emp 5 start with mgr is null 6 connect by mgr = prior empno 7 order siblings by empno ); LVL EMPNO ENAME RN ---------- ---------- -------------------- ---------- 1 7839 KING 1 2 7566 JONES 2 3 7788 SCOTT 3 4 7876 ADAMS 4 3 7902 FORD 5 4 7369 SMITH 6 2 7698 BLAKE 7 3 7499 ALLEN 8 3 7521 WARD 9 3 7654 MARTIN 10 3 7844 TURNER 11 3 7900 JAMES 12 2 7782 CLARK 13 3 7934 MILLER 14 135 "starting level" "next level higher then starting level?"
  • 136. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select lvl, empno, ename, rownum as rn 2 from ( 3 select level as lvl, empno, ename 4 from emp 5 start with mgr is null 6 connect by mgr = prior empno 7 order siblings by empno ); LVL EMPNO ENAME RN ---------- ---------- -------------------- ---------- 1 7839 KING 1 2 7566 JONES 2 3 7788 SCOTT 3 4 7876 ADAMS 4 3 7902 FORD 5 4 7369 SMITH 6 2 7698 BLAKE 7 3 7499 ALLEN 8 3 7521 WARD 9 3 7654 MARTIN 10 3 7844 TURNER 11 3 7900 JAMES 12 2 7782 CLARK 13 3 7934 MILLER 14 136 "starting level" "next level higher then starting level?"
  • 137. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select lvl, empno, ename, rownum as rn 2 from ( 3 select level as lvl, empno, ename 4 from emp 5 start with mgr is null 6 connect by mgr = prior empno 7 order siblings by empno ); LVL EMPNO ENAME RN ---------- ---------- -------------------- ---------- 1 7839 KING 1 2 7566 JONES 2 3 7788 SCOTT 3 4 7876 ADAMS 4 3 7902 FORD 5 4 7369 SMITH 6 2 7698 BLAKE 7 3 7499 ALLEN 8 3 7521 WARD 9 3 7654 MARTIN 10 3 7844 TURNER 11 3 7900 JAMES 12 2 7782 CLARK 13 3 7934 MILLER 14 137 "Done! How many?"
  • 138. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> with raw_data as ( 2 select lvl, empno, ename, rownum as rn 3 from ( select level as lvl, empno, ename 4 from emp 5 start with mgr is null 6 connect by mgr = prior empno 7 order siblings by empno ) 8 ) ... 138 as before
  • 139. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | ... 9 select empno 10 , lpad(' ', (lvl-1)*2) || ename as ename 11 , reports 12 from raw_data 13 match_recognize ( 14 order by rn 15 measures 16 starting_level.rn as rn 17 , starting_level.lvl as lvl 18 , starting_level.empno as empno 19 , starting_level.ename as ename 20 , count(higher_level.lvl) as reports 21 one row per match 22 after match skip to next row 23 pattern (starting_level higher_level*) 24 define higher_level as lvl > starting_level.lvl 25 ) 26 order by rn; 139
  • 140. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> with raw_data as ( 2 select lvl, empno, ename, rownum as rn 3 from ( select level as lvl, empno, ename 4 from emp 5 start with mgr is null 6 connect by mgr = prior empno 7 order siblings by empno ) 8 ) 9 select empno 10 , lpad(' ', (lvl-1)*2) || ename as ename 11 , reports 12 from raw_data 13 match_recognize ( 14 order by rn 15 measures 16 starting_level.rn as rn 17 , starting_level.lvl as lvl 18 , starting_level.empno as empno 19 , starting_level.ename as ename 20 , count(higher_level.lvl) as reports 21 one row per match 22 pattern (starting_level higher_level*) 23 define higher_level as lvl > starting_level.lvl 24 ) 25 order by rn; EMPNO ENAME REPORTS ---------- -------------------- ---------- 7839 KING 13 140
  • 141. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | 141
  • 142. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select lvl, empno, ename, rownum as rn 2 from ( 3 select level as lvl, empno, ename 4 from emp 5 start with mgr is null 6 connect by mgr = prior empno 7 order siblings by empno ); LVL EMPNO ENAME RN ---------- ---------- -------------------- ---------- 1 7839 KING 1 2 7566 JONES 2 3 7788 SCOTT 3 4 7876 ADAMS 4 3 7902 FORD 5 4 7369 SMITH 6 2 7698 BLAKE 7 3 7499 ALLEN 8 3 7521 WARD 9 3 7654 MARTIN 10 3 7844 TURNER 11 3 7900 JAMES 12 2 7782 CLARK 13 3 7934 MILLER 14 142
  • 143. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select lvl, empno, ename, rownum as rn 2 from ( 3 select level as lvl, empno, ename 4 from emp 5 start with mgr is null 6 connect by mgr = prior empno 7 order siblings by empno ); LVL EMPNO ENAME RN ---------- ---------- -------------------- ---------- 1 7839 KING 1 2 7566 JONES 2 3 7788 SCOTT 3 4 7876 ADAMS 4 3 7902 FORD 5 4 7369 SMITH 6 2 7698 BLAKE 7 3 7499 ALLEN 8 3 7521 WARD 9 3 7654 MARTIN 10 3 7844 TURNER 11 3 7900 JAMES 12 2 7782 CLARK 13 3 7934 MILLER 14 143
  • 144. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | "done!" 144
  • 145. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | ... 9 select empno 10 , lpad(' ', (lvl-1)*2) || ename as ename 11 , reports 12 from raw_data 13 match_recognize ( 14 order by rn 15 measures 16 starting_level.rn as rn 17 , starting_level.lvl as lvl 18 , starting_level.empno as empno 19 , starting_level.ename as ename 20 , count(higher_level.lvl) as reports 21 one row per match 22 after match skip to next row 23 pattern (starting_level higher_level*) 24 define higher_level as lvl > starting_level.lvl 25 ) 26 order by rn; 145
  • 146. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> with raw_data as ( ... 9 select empno 10 , lpad(' ', (lvl-1)*2) || ename as ename 11 , reports 12 from raw_data 13 match_recognize ( 14 order by rn 15 measures 16 starting_level.rn as rn 17 , starting_level.lvl as lvl 18 , starting_level.empno as empno 19 , starting_level.ename as ename 20 , count(higher_level.lvl) as reports 21 one row per match 22 after match skip to next row 23 pattern (starting_level higher_level*) 24 define higher_level as lvl > starting_level.lvl 25 ) 26 order by rn; EMPNO ENAME REPORTS ---------- -------------------- ---------- 7839 KING 13 7566 JONES 4 7788 SCOTT 1 7876 ADAMS 0 7902 FORD 1 7369 SMITH 0 7698 BLAKE 5 7499 ALLEN 0 ... 146
  • 147. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | 147 the power of a single SQL
  • 148. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |148 select ename from emp where empno = :1 select sum(...) from emp, dept group by ... select min(..) keep ( dense_rank ) ... from emp ... select ... from emp match_recognize measures define ...
  • 149. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | 149 what if it doesn't work ?
  • 150. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | 150 "What I need" "Hell yeah!"
  • 151. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | 151 3GL ... we debug
  • 152. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | procedure check_auto_no_new_questions is l_app_controls_rec ate_application_controls%rowtype; l_auto_no_new_limit number; l_new_never_read_cnt number; begin msg('Checking metadata'); select * into l_app_controls_rec from ate_application_controls where application_code = 'NONEW'; if l_app_controls_rec.enabled = 'Y' then msg('NONEW'); return; end if; msg('l_new_never_read_cnt='||l_new_never_read_cnt ); msg('l_auto_no_new_limit ='||l_new_never_read_cnt ); if l_new_never_read_cnt >= l_auto_no_new_limit then msg('Turning off settings'); update ate_application_controls set enabled = 'Y' where application_code = 'NONEW'; ... 152
  • 153. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select customer, growth_class, startdate, start_txn, enddate, 2 end_txn, avg_daily_txn 3 from cust_summary 4 match_recognize ( 5 partition by customer order by dte 6 measures 7 final last(dte) as termdate 8 , first(dte) as startdate 9 , first(cumu_txns) as start_txn 10 , last(dte) as enddate 11 , next(cumu_txns) as end_txn 12 , (next(cumu_txns) - first(cumu_txns)) / count(*) as avg_daily_txn 13 one row per match after match skip past last row 14 pattern ( fast+ | slow{3,} ) 15 define fast as next(cumu_txns) / cumu_txns >= 1.20 16 , slow as next(slow.cumu_txns) / slow.cumu_txns >= 1.10 and 17 next(slow.cumu_txns) / slow.cumu_txns < 1.20 18 ) 19 order by customer, startdate; 153
  • 154. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | 154
  • 155. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | match_number() 155
  • 156. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | "Hello World" 156
  • 157. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select * from t 2 match_recognize ( order by x 3 measures 4 first(x) lo 5 , last(x) hi 6 , count(*) range 7 one row per match 8 pattern ( any_old_row contig* ) 9 define contig as x = prev(x) + 1 ); LO HI RANGE ---------- ---------- ---------- 1 3 3 5 6 2 9 11 3 16 17 2 19 19 1 21 21 1 30 30 1 157
  • 158. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select * from t 2 match_recognize ( order by x 3 measures 4 first(x) lo 5 , last(x) hi 6 , count(*) range 7 , match_number() as mn 8 all rows per match 9 pattern ( any_old_row contig* ) 10 define contig as x = prev(x) + 1 ); X LO HI RANGE MN ---------- ---------- ---------- ---------- ---------- 1 1 1 1 1 2 1 2 2 1 3 1 3 3 1 5 5 5 1 2 6 5 6 2 2 9 9 9 1 3 10 9 10 2 3 11 9 11 3 3 16 16 16 1 4 17 16 17 2 4 19 19 19 1 5 21 21 21 1 6 30 30 30 1 7 158
  • 159. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | classifier() 159
  • 160. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select * from t 2 match_recognize ( order by x 3 measures 4 first(x) lo 5 , last(x) hi 6 , count(*) range 7 , match_number() as mn 8 , classifier() as cl 9 all rows per match 10 pattern ( any_old_row contig* ) 11 define contig as x = prev(x) + 1 ); X LO HI RANGE MN CL ---------- ---------- ---------- ---------- ---------- ------------- 1 1 1 1 1 ANY_OLD_ROW 2 1 2 2 1 CONTIG 3 1 3 3 1 CONTIG 5 5 5 1 2 ANY_OLD_ROW 6 5 6 2 2 CONTIG 9 9 9 1 3 ANY_OLD_ROW 10 9 10 2 3 CONTIG 11 9 11 3 3 CONTIG 16 16 16 1 4 ANY_OLD_ROW 17 16 17 2 4 CONTIG 19 19 19 1 5 ANY_OLD_ROW 21 21 21 1 6 ANY_OLD_ROW 30 30 30 1 7 ANY_OLD_ROW 160
  • 161. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | not just debugging 161
  • 162. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | useful for grouping 162
  • 163. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | "groupings of decline in expenditure" 163 http://www.kibeha.dk/2015/07/row-pattern-matching-nested-within.html
  • 164. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select * from company_sal order by start_date desc; START_DAT EXPENDITURE --------- ----------- 01-JAN-16 12880.45 01-JUL-15 12880.45 01-JUL-12 12880.45 01-FEB-12 12880.45 01-JUL-11 13421.7 01-JUL-10 12880.45 16-JUN-10 12880.45 01-APR-10 13421.7 01-NOV-09 12881.39 01-JUL-09 12361.93 01-JUL-08 12361.93 01-APR-08 12361.93 01-JUL-07 11843.41 01-JUL-06 11843.41 01-MAY-06 11843.41 01-APR-06 11843.41 01-JUL-05 11324.9 01-JUL-04 11324.9 01-MAY-04 11324.9 01-APR-04 11324.9 01-JAN-04 10806.37 01-JUL-02 10806.37 16-APR-02 10806.37 164 GRP ---------- 1 1 1 1 2 2 2 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3 3
  • 165. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select * from company_sal 2 match_recognize ( 3 order by start_date desc 4 measures 5 match_number() grp 6 all rows per match 7 pattern ( always_true headin_down* ) 8 define 9 headin_down as ( 10 headin_down.expenditure <= prev(headin_down.expenditure) 11 ) 12 ) 13 order by start_date desc ; 165
  • 166. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select * from company_sal 2 match_recognize ( 3 order by start_date desc 4 measures 5 match_number() grp 6 all rows per match 7 pattern ( always_true headin_down* ) 8 define 9 headin_down as ( 10 headin_down.expenditure <= prev(headin_down.expenditure) 11 ) 12 ) order by start_date desc ; START_DAT GRP EXPENDITURE --------- ---------- ----------- 01-JAN-16 1 12880.45 01-JUL-15 1 12880.45 01-JUL-12 1 12880.45 01-FEB-12 1 12880.45 01-JUL-11 2 13421.7 01-JUL-10 2 12880.45 16-JUN-10 2 12880.45 01-APR-10 3 13421.7 01-NOV-09 3 12881.39 01-JUL-09 3 12361.93 01-JUL-08 3 12361.93 01-APR-08 3 12361.93 ... 01-JUL-02 3 10806.37 16-APR-02 3 10806.37 166
  • 167. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | aggregates as patterns 167
  • 168. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | "If customers hit their minimum shipping target, ship that batch now. Otherwise ship their stuff after 30 days" 168 http://www.kibeha.dk/2015/07/row-pattern-matching-nested-within.html
  • 169. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> desc CUST Name Null? Type ----------------------------- -------- ---------------- CUST_ID NUMBER(38) CUST_NAME VARCHAR2(30) MIN_SHIP_VALUE NUMBER(38) SQL> desc CUST_ORDERS Name Null? Type ----------------------------- -------- ---------------- CUST_ID NUMBER ORDER_NO NUMBER AMT NUMBER(38) SHIP_DATE DATE 169
  • 170. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select * from cust; CUST_ID CUST_NAME MIN_SHIP_VALUE ---------- ------------------------------ -------------- 1 Cust A 350 2 Cust B 750 SQL> select * 2 from cust_orders co 3 order by cust_id, ship_date, order_no; CUST_ID ORDER_NO AMT SHIP_DATE ---------- ---------- ---------- --------- 1 11 100 31-JAN-17 1 13 10 10-FEB-17 1 12 250 11-FEB-17 1 21 1000 21-FEB-17 1 31 4000 31-MAR-17 2 41 175 31-JAN-17 2 51 100 10-FEB-17 2 42 500 11-FEB-17 2 52 1000 21-FEB-17 2 61 100 31-MAR-17 170
  • 171. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select * from cust; CUST_ID CUST_NAME MIN_SHIP_VALUE ---------- ------------------------------ -------------- 1 Cust A 350 2 Cust B 750 SQL> select * 2 from cust_orders co 3 order by cust_id, ship_date, order_no; CUST_ID ORDER_NO AMT SHIP_DATE ---------- ---------- ---------- --------- 1 11 100 31-JAN-17 1 13 10 10-FEB-17 1 12 250 11-FEB-17 1 21 1000 21-FEB-17 1 31 4000 31-MAR-17 2 41 175 31-JAN-17 2 51 100 10-FEB-17 2 42 500 11-FEB-17 2 52 1000 21-FEB-17 2 61 100 31-MAR-17 171
  • 172. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select * from cust; CUST_ID CUST_NAME MIN_SHIP_VALUE ---------- ------------------------------ -------------- 1 Cust A 350 2 Cust B 750 SQL> select * 2 from cust_orders co 3 order by cust_id, ship_date, order_no; CUST_ID ORDER_NO AMT SHIP_DATE ---------- ---------- ---------- --------- 1 11 100 31-JAN-17 1 13 10 10-FEB-17 1 12 250 11-FEB-17 1 21 1000 21-FEB-17 1 31 4000 31-MAR-17 2 41 175 31-JAN-17 2 51 100 10-FEB-17 2 42 500 11-FEB-17 2 52 1000 21-FEB-17 2 61 100 31-MAR-17 172
  • 173. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | pattern 173 "any number under the shipping limit" UNDER_LIMIT* "then hit/exceed the shipping limit" OVER_LIMIT "some might never hit the shipping limit" {0,1}
  • 174. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | definitions 174 UNDER_LIMIT OVER_LIMIT "rolling" sum(amt) < cust.min_ship_limit "rolling" sum(amt) >= cust.min_ship_limit
  • 175. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | recall 175
  • 176. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select * from t 2 match_recognize ( order by x 3 measures ... pattern ... 4 DEFINE 5 p1 as x = 1 6 , p2 as first(x) = 1 7 , p3 as last(x) = 1 8 , p4 as prev(x) = 1 9 , p5 as next(x) = 1 10 , p6 as count(*) = 1 11 , p7 as final last(x) = 1 12 , p8 as contig.x = 1 13 , p9 as count(contig.*) = 1 14 ); 176 as per ALL ROWS PER MATCH - this row - first row of match pattern - this row - previous row from this row - next row from this row - count from first to this row - ILLEGAL - this 'contig' row - count from first to this contig row
  • 177. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select * from ( 2 select co.*, c.min_ship_value 3 from cust c, cust_orders co 4 where c.cust_id = co.cust_id 5 ) 6 match_recognize ( 7 partition by cust_id 8 order by ship_date, order_no 9 measures 10 match_number() as mno, 11 classifier() as cls, 12 sum(amt) as tot 13 all rows per match 14 pattern ( under_limit* over_limit{0,1} ) 15 define 16 under_limit as sum(amt) < min_ship_value, 17 over_limit as sum(amt) >= min_ship_value ); CUST_ID SHIP_DATE ORDER_NO MNO CLS TOT AMT MIN_SHIP_VALUE ---------- --------- ---------- ----- --------------- ---------- ---------- -------------- 1 31-JAN-17 11 1 UNDER_LIMIT 100 100 350 1 10-FEB-17 13 1 UNDER_LIMIT 110 10 350 1 11-FEB-17 12 1 OVER_LIMIT 360 250 350 1 21-FEB-17 21 2 OVER_LIMIT 1000 1000 350 1 31-MAR-17 31 3 OVER_LIMIT 4000 4000 350 2 31-JAN-17 41 1 UNDER_LIMIT 175 175 750 2 10-FEB-17 51 1 UNDER_LIMIT 275 100 750 2 11-FEB-17 42 1 OVER_LIMIT 775 500 750 2 21-FEB-17 52 2 OVER_LIMIT 1000 1000 750 2 31-MAR-17 61 3 UNDER_LIMIT 100 100 750 177
  • 178. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | "If customers hit their minimum shipping target, ship that batch now. Otherwise ship their stuff after 30 days" 178 http://www.kibeha.dk/2015/07/row-pattern-matching-nested-within.html
  • 179. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select * from ( 2 select co.*, c.min_ship_value 3 from cust c, cust_orders co 4 where c.cust_id = co.cust_id 5 ) 6 match_recognize ( 7 partition by cust_id 8 order by ship_date, order_no 9 measures 10 match_number() as mno, 11 classifier() as cls, 12 sum(amt) as tot, 13 nvl(final last(over_limit.ship_date), last(ship_date)+30) last_ship_date 14 all rows per match 15 pattern ( under_limit* over_limit{0,1} ) 16 define 17 under_limit as sum(amt) < min_ship_value, 18 over_limit as sum(amt) >= min_ship_value ); 179
  • 180. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | pattern aggregates as measures 180
  • 181. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | "W patterns in sales transactions" 181
  • 182. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |182
  • 183. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |183 slope1 = amt < prev(amt) slope2 = amt > prev(amt) slope3 = amt < prev(amt) slope4 = amt < prev(amt) pattern = ( slope1+ slope2+ slope3+ slope4+ )
  • 184. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | "average AMT in the matched W" 184
  • 185. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |185 slope1 = amt < prev(amt) slope2 = amt > prev(amt) slope3 = amt < prev(amt) slope4 = amt < prev(amt) pattern = ( slope1+ slope2+ slope3+ slope4+ ) measures avg(amt) as w_average
  • 186. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | "average AMT in first downward slide" 186
  • 187. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |187 slope1 = amt < prev(amt) slope2 = amt > prev(amt) slope3 = amt < prev(amt) slope4 = amt < prev(amt) pattern = ( slope1+ slope2+ slope3+ slope4+ ) measures avg(slope1.amt) as slide_avg
  • 188. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | pattern subsets 188
  • 189. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | "average AMT in first V of the W" 189
  • 190. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |190 slope1 = amt < prev(amt) slope2 = amt > prev(amt) slope3 = amt < prev(amt) slope4 = amt < prev(amt) pattern = ( slope1+ slope2+ slope3+ slope4+ ) subset s1s2 = ( slope1,slope2) measures avg(s1s2.amt) as slide_avg
  • 191. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | pattern aggregates as predicates 191
  • 192. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | "W patterns in sales transactions, capped at 7 days" 192
  • 193. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. |193 slope1 = amt < prev(amt) slope2 = amt > prev(amt) slope3 = amt < prev(amt) slope4 = amt < prev(amt) and slope4.dte - first(slope1.dte) < 7 Apr 3 Apr 8
  • 194. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | not so obvious patterns 194
  • 195. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select * from t 2 order by sample_result_key, result_date; SAMPLE_RESULT_KEY RESULT_DA RESULT_VALUE ----------------- --------- ------------ 1 01-JUN-14 4 1 03-JUN-14 5 1 06-JUN-14 4 1 07-JUN-14 3 1 09-JUN-14 7.2 1 14-JUN-14 8 1 15-JUN-14 10 1 17-JUN-14 0 2 01-JUL-14 11.55 2 03-JUL-14 11.35 2 06-JUL-14 5.43 2 07-JUL-14 7.74 2 09-JUL-14 7.27 2 14-JUL-14 7.84 2 15-JUL-14 9.54 2 17-JUL-14 10.42 195 "For the maximum date per sample, return the value. But if its zero, return the lowest value within the last 7 days
  • 196. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select * from t 2 order by sample_result_key, result_date desc; SAMPLE_RESULT_KEY RESULT_DA RESULT_VALUE ----------------- --------- ------------ 1 17-JUN-14 0 1 15-JUN-14 10 1 14-JUN-14 8 1 09-JUN-14 7.2 1 07-JUN-14 3 1 06-JUN-14 4 1 03-JUN-14 5 1 01-JUN-14 4 2 17-JUL-14 10.42 2 15-JUL-14 9.54 2 14-JUL-14 7.84 2 09-JUL-14 7.27 2 07-JUL-14 7.74 2 06-JUL-14 5.43 2 03-JUL-14 11.35 2 01-JUL-14 11.55 196
  • 197. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | pattern (^starting_pos boundary*) define boundary as starting_pos.result_value = 0 and result_date >= starting_pos.result_date - 7 and result_value = min(result_value) 197 start with first row per sample when that row is zero, match forward up to 7 days and pick the lowest value
  • 198. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select * from t 2 match_recognize( 3 partition by sample_result_key 4 order by result_date desc 5 measures 6 match_number() as mn, 7 classifier() as cl, 8 starting_pos.result_date rd1, 9 result_value rv1 10 all rows per match 11 pattern (^starting_pos boundary*) 12 define 13 boundary as starting_pos.result_value = 0 and 14 result_date >= starting_pos.result_date - 7 15 and result_value = min(result_value) 16 ); SAMPLE_RESULT_KEY RESULT_DA MN CL RD1 RV1 RESULT_VALUE ----------------- --------- ---------- -------------- --------- ---------- ------------ 1 17-JUN-14 1 STARTING_POS 17-JUN-14 0 0 2 17-JUL-14 1 STARTING_POS 17-JUL-14 10.42 10.42 198 includes the zero row
  • 199. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | pattern (^starting_pos boundary*) define not_so_restrictive as starting_pos.result_value = 0 and result_date >= starting_pos.result_date - 7, boundary as starting_pos.result_value = 0 and result_date >= starting_pos.result_date - 7 and result_value = min(result_value) 199
  • 200. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select * from t 2 match_recognize( 3 partition by sample_result_key 4 order by result_date desc 5 measures 6 match_number() as mn, 7 classifier() as cl, 8 starting_pos.result_date rd1, 9 result_value rv1 10 all rows per match 11 pattern (^starting_pos (boundary|not_so_restrictive)*) 12 define 13 not_so_restrictive as starting_pos.result_value = 0 and 14 result_date >= starting_pos.result_date - 7, 15 boundary as starting_pos.result_value = 0 and 16 result_date >= starting_pos.result_date - 7 and 17 result_value = min(result_value) 18 ); SAMPLE_RESULT_KEY RESULT_DA MN CL RD1 RV1 RESULT_VALUE ----------------- --------- ---------- -------------------- --------- ---------- ------------ 1 17-JUN-14 1 STARTING_POS 17-JUN-14 0 0 1 15-JUN-14 1 NOT_SO_RESTRICTIVE 17-JUN-14 10 10 1 14-JUN-14 1 NOT_SO_RESTRICTIVE 17-JUN-14 8 8 2 17-JUL-14 1 STARTING_POS 17-JUL-14 10.42 10.42 200
  • 201. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select * from t 2 match_recognize( 3 partition by sample_result_key 4 order by result_date desc 5 measures 6 match_number() as mn, 7 classifier() as cl, 8 starting_pos.result_date rd1, 9 result_value rv1 10 all rows per match 11 pattern (^starting_pos (boundary|not_so_restrictive)*) 12 define 13 not_so_restrictive as starting_pos.result_value = 0 and 14 result_date >= starting_pos.result_date - 7, 15 boundary as starting_pos.result_value = 0 and 16 result_date >= starting_pos.result_date - 7 and 17 result_value = min(result_value) 18 ); SAMPLE_RESULT_KEY MN CL RD1 RV1 ----------------- ---------- -------------------- --------- ---------- 1 1 NOT_SO_RESTRICTIVE 17-JUN-14 8 2 1 STARTING_POS 17-JUL-14 10.42 201
  • 202. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | 202
  • 203. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | "Divides a set of weights into 3 equi-sized buckets" 203 https://stewashton.wordpress.com/2014/06/06/bin-fitting-problems-with-sql/
  • 204. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select * from t; KG ---------- 1 3 4 6 7 8 11 12 13 14 17 18 19 204 1 3 4 6 7 8 11 12 13 14 17 18 19
  • 205. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | pattern ( (bin1|bin2|bin3)* ) define bin1 as count(bin1.*) = 1 or sum(bin1.kg) <= least(sum(bin2.kg), sum(bin3.kg) , bin2 as count(bin2.*) = 1 or sum(bin2.kg)-bin2.kg <= sum(bin3.kg) 205 I will want 3 bins (matching my as yet unknown rules) the bin is empty - bin1.kg my bin has less than either of the other two bins ... so far use my bin if ...
  • 206. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select * 2 from t 3 match_recognize ( 4 order by kg desc 5 measures 6 classifier() bin#, 7 sum(bin1.kg) bin1, 8 sum(bin2.kg) bin2, 9 sum(bin3.kg) bin3 10 all rows per match 11 pattern ( 12 (bin1|bin2|bin3)* 13 ) 14 define 15 bin1 as count(bin1.*) = 1 or 16 sum(bin1.kg)-bin1.kg <= least(sum(bin2.kg), sum(bin3.kg)) 17 , bin2 as count(bin2.*) = 1 or 18 sum(bin2.kg)-bin2.kg <= sum(bin3.kg) 19 ); 206
  • 207. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | KG BIN# BIN1 BIN2 BIN3 ---------- ------ ---------- ---------- ---------- 19 BIN1 19 18 BIN2 19 18 17 BIN3 19 18 17 14 BIN3 19 18 31 13 BIN2 19 31 31 12 BIN1 31 31 31 11 BIN1 42 31 31 8 BIN2 42 39 31 7 BIN3 42 39 38 6 BIN3 42 39 44 4 BIN2 42 43 44 3 BIN1 45 43 44 1 BIN2 45 44 44 207
  • 208. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | SQL> select * 2 from t 3 match_recognize ( 4 order by kg desc 5 measures 6 sum(bin1.kg) bin1, 7 sum(bin2.kg) bin2, 8 sum(bin3.kg) bin3 9 pattern ( 10 (bin1|bin2|bin3)* 11 ) 12 define 13 bin1 as count(bin1.*) = 1 or 14 sum(bin1.kg)-bin1.kg <= least(sum(bin2.kg), sum(bin3.kg)) 15 , bin2 as count(bin2.*) = 1 or 16 sum(bin2.kg)-bin2.kg <= sum(bin3.kg) 17 ); BIN1 BIN2 BIN3 ---------- ---------- ---------- 45 44 44 208
  • 209. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | 209 wrap up
  • 210. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | 210
  • 211. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | 211 be patient
  • 212. Copyright © 2016, Oracle and/or its affiliates. All rights reserved. | Enjoy the day! youtube bit.ly/youtube-connor blog bit.ly/blog-connor twitter bit.ly/twitter-connor 400+ posts mainly on database & development 250 technical videos, new uploads every week rants and raves on tech and the world :-)

Editor's Notes

  1. which of course means, we really should not be surprised when ask our customers about performance
  2. (outline to be removed) and that is a problem …. especially in a future autonomous world. Your distance from the customer … especially if you happen LIKE that distance by (say) being silo'd off in an IT department cubicle … is related to your job prospects!
  3. (outline to be removed) and that is a problem …. especially in a future autonomous world. Your distance from the customer … especially if you happen LIKE that distance by (say) being silo'd off in an IT department cubicle … is related to your job prospects!
  4. (outline to be removed) and that is a problem …. especially in a future autonomous world. Your distance from the customer … especially if you happen LIKE that distance by (say) being silo'd off in an IT department cubicle … is related to your job prospects!
  5. (outline to be removed) and that is a problem …. especially in a future autonomous world. Your distance from the customer … especially if you happen LIKE that distance by (say) being silo'd off in an IT department cubicle … is related to your job prospects!
  6. (outline to be removed) and that is a problem …. especially in a future autonomous world. Your distance from the customer … especially if you happen LIKE that distance by (say) being silo'd off in an IT department cubicle … is related to your job prospects!
  7. (outline to be removed) and that is a problem …. especially in a future autonomous world. Your distance from the customer … especially if you happen LIKE that distance by (say) being silo'd off in an IT department cubicle … is related to your job prospects!
  8. (outline to be removed) and that is a problem …. especially in a future autonomous world. Your distance from the customer … especially if you happen LIKE that distance by (say) being silo'd off in an IT department cubicle … is related to your job prospects!