View
1.516
Download
0
Category
Preview:
Citation preview
Row Pattern Matching Availability19
99
2001
2003
2005
2007
2009
2011
2013
2015
MariaDBMySQLPostgreSQLSQLite
DB2 LUW12cR1 Oracle
SQL Server
Grouping Consecutive Events
Example: Logfile
Time
30 minutes
Session 1 Session 2 Session 3
Session 4
Example problems:
‣ Count sessions
‣ Average session duration
Two approaches:
‣ Start-of-group tagging
‣ Row pattern matching
SELECTCOUNT(grp_start)groupsFROM(SELECTCASEWHENts>LAG(ts,1,DATE'1900-01-01')OVER(ORDERBYts)+INTERVAL'30'minuteTHEN1ENDgrp_startFROMlog)T
Consecutive Events: Counting Start-of-group tagging
Time
30 minutes
SELECTCOUNT(grp_start)groupsFROM(SELECTCASEWHENts>LAG(ts,1,DATE'1900-01-01')OVER(ORDERBYts)+INTERVAL'30'minuteTHEN1ENDgrp_startFROMlog)T
Consecutive Events: Counting Start-of-group tagging
Time
30 minutes
count thenon-NULL
values
SELECTCOUNT(*)sessionsFROMlogMATCH_RECOGNIZE(ORDERBYtsPATTERN(new)DEFINEnewASts>COALESCE(PREV(ts),DATE'1900-01-01')+INTERVAL'30'minute)t
Consecutive Events: Counting Row Pattern Matching
Time
30 minutes
SELECTCOUNT(*)sessionsFROMlogMATCH_RECOGNIZE(ORDERBYtsPATTERN(new)DEFINEnewASts>COALESCE(PREV(ts),DATE'1900-01-01')+INTERVAL'30'minute)t
Consecutive Events: Counting Row Pattern Matching
Time
30 minutes
row pattern variable
SELECTCOUNT(*)sessionsFROMlogMATCH_RECOGNIZE(ORDERBYtsPATTERN(new)DEFINEnewASts>COALESCE(PREV(ts),DATE'1900-01-01')+INTERVAL'30'minute)t
Consecutive Events: Counting Row Pattern Matching
Time
30 minutes
match only “new”
rows
SELECTCOUNT(*)sessionsFROMlogMATCH_RECOGNIZE(ORDERBYtsPATTERN(new)DEFINEnewASts>COALESCE(PREV(ts),DATE'1900-01-01')+INTERVAL'30'minute)t
Consecutive Events: Counting Row Pattern Matching
Time
30 minutes
countrows
SELECTCOUNT(*)sessions,AVG(duration)avg_durationFROMlogMATCH_RECOGNIZE(ORDERBYtsMEASURESLAST(ts)-FIRST(ts)ASdurationONEROWPERMATCHPATTERN(newcont*)DEFINEcontASts<PREV(ts)+INTERVAL'30'minute)t
Row Pattern MatchingConsecutive Events: Statistics
Time
30 minutes
definecontinuation
Oracle doesn’t support avg on intervals — query doesn’t work as shown
SELECTCOUNT(*)sessions,AVG(duration)avg_durationFROMlogMATCH_RECOGNIZE(ORDERBYtsMEASURESLAST(ts)-FIRST(ts)ASdurationONEROWPERMATCHPATTERN(newcont*)DEFINEcontASts<PREV(ts)+INTERVAL'30'minute)t
Row Pattern MatchingConsecutive Events: Statistics
Time
30 minutes
undefinedpattern variable: matches any row
Oracle doesn’t support avg on intervals — query doesn’t work as shown
SELECTCOUNT(*)sessions,AVG(duration)avg_durationFROMlogMATCH_RECOGNIZE(ORDERBYtsMEASURESLAST(ts)-FIRST(ts)ASdurationONEROWPERMATCHPATTERN(newcont*)DEFINEcontASts<PREV(ts)+INTERVAL'30'minute)t
Row Pattern MatchingConsecutive Events: Statistics
Time
30 minutes
any numberof “cont”
rows
Oracle doesn’t support avg on intervals — query doesn’t work as shown
SELECTCOUNT(*)sessions,AVG(duration)avg_durationFROMlogMATCH_RECOGNIZE(ORDERBYtsMEASURESLAST(ts)-FIRST(ts)ASdurationONEROWPERMATCHPATTERN(newcont*)DEFINEcontASts<PREV(ts)+INTERVAL'30'minute)t
Row Pattern MatchingConsecutive Events: Statistics
Time
30 minutes
Very muchlike GROUP BY
Oracle doesn’t support avg on intervals — query doesn’t work as shown
SELECTCOUNT(*)sessions,AVG(duration)avg_durationFROMlogMATCH_RECOGNIZE(ORDERBYtsMEASURESLAST(ts)-FIRST(ts)ASdurationONEROWPERMATCHPATTERN(newcont*)DEFINEcontASts<PREV(ts)+INTERVAL'30'minute)t
Row Pattern MatchingConsecutive Events: Statistics
Time
30 minutes
Very muchlike SELECT
Oracle doesn’t support avg on intervals — query doesn’t work as shown
SELECTCOUNT(*)sessions,AVG(duration)avg_durationFROMlogMATCH_RECOGNIZE(ORDERBYtsMEASURESLAST(ts)-FIRST(ts)ASdurationONEROWPERMATCHPATTERN(newcont*)DEFINEcontASts<PREV(ts)+INTERVAL'30'minute)t
Row Pattern MatchingConsecutive Events: Statistics
Time
30 minutes
Oracle doesn’t support avg on intervals — query doesn’t work as shown
Consecutive Events: Statistics Start-of-group tagging
Time
30 minutes
Now, let’s try using window functions
SELECTcount(*)sessions,avg(duration)avg_durationFROM(SELECTMAX(ts)-MIN(ts)durationFROM(SELECTts,COUNT(grp_start)OVER(ORDERBYts)session_noFROM(SELECTts,CASEWHENts>=LAG(ts,1,DATE’1900-01-1')OVER(ORDERBYts)+INTERVAL'30'minuteTHEN1ENDgrp_startFROMlog)tagged)numberedGROUPBYsession_no)grouped
Consecutive Events: Statistics Start-of-group tagging
Time
30 minutes
Start-of-group tags
SELECTcount(*)sessions,avg(duration)avg_durationFROM(SELECTMAX(ts)-MIN(ts)durationFROM(SELECTts,COUNT(grp_start)OVER(ORDERBYts)session_noFROM(SELECTts,CASEWHENts>=LAG(ts,1,DATE’1900-01-1')OVER(ORDERBYts)+INTERVAL'30'minuteTHEN1ENDgrp_startFROMlog)tagged)numberedGROUPBYsession_no)grouped
Consecutive Events: Statistics Start-of-group tagging
Time
30 minutes
number sessions
2222 2 33 3 44 42 3 41
SELECTcount(*)sessions,avg(duration)avg_durationFROM(SELECTMAX(ts)-MIN(ts)durationFROM(SELECTts,COUNT(grp_start)OVER(ORDERBYts)session_noFROM(SELECTts,CASEWHENts>=LAG(ts,1,DATE’1900-01-1')OVER(ORDERBYts)+INTERVAL'30'minuteTHEN1ENDgrp_startFROMlog)tagged)numberedGROUPBYsession_no)grouped
Consecutive Events: Statistics Start-of-group tagging
Time
30 minutes 2222 2 33 3 44 42 3 41
SELECTcount(*)sessions,avg(duration)avg_durationFROM(SELECTMAX(ts)-MIN(ts)durationFROM(SELECTts,COUNT(grp_start)OVER(ORDERBYts)session_noFROM(SELECTts,CASEWHENts>=LAG(ts,1,DATE’1900-01-1')OVER(ORDERBYts)+INTERVAL'30'minuteTHEN1ENDgrp_startFROMlog)tagged)numberedGROUPBYsession_no)grouped
Consecutive Events: Statistics Start-of-group tagging
Time
30 minutes
4 Levels: 2 with window functions
2 for grouping
What about performance?
2222 2 33 3 44 42 3 41
Tolerating Gaps
Example: Comments (new vs. read)
Show comments which…
‣…are new or
‣…between two new ones (show the comment instead of a “load more” button)
Two approaches:
‣ Start-of-group tagging
‣ Row pattern matching
Comments
new comment read comment
SELECTid,markerFROMmsgMATCH_RECOGNIZE(ORDERBYidALLROWSPERMATCHPATTERN(new+(readnew+)*)DEFINEnewAS(marker='X'))TORDERBYid
Tolerating Gaps Row Pattern Matching
Comments
Start with oneor more NEWcomment(s)
SELECTid,markerFROMmsgMATCH_RECOGNIZE(ORDERBYidALLROWSPERMATCHPATTERN(new+(readnew+)*)DEFINEnewAS(marker='X'))TORDERBYid
Tolerating Gaps Row Pattern Matching
Comments
Start with oneor more NEWcomment(s)
Doesn’t match
SELECTid,markerFROMmsgMATCH_RECOGNIZE(ORDERBYidALLROWSPERMATCHPATTERN(new+(readnew+)*)DEFINEnewAS(marker='X'))TORDERBYid
Tolerating Gaps Row Pattern Matching
Comments
Start with oneor more NEWcomment(s)
Two rows match “new+”
SELECTid,markerFROMmsgMATCH_RECOGNIZE(ORDERBYidALLROWSPERMATCHPATTERN(new+(readnew+)*)DEFINEnewAS(marker='X'))TORDERBYid
Tolerating Gaps Row Pattern Matching
Comments
Match exactlyone row (any)
SELECTid,markerFROMmsgMATCH_RECOGNIZE(ORDERBYidALLROWSPERMATCHPATTERN(new+(readnew+)*)DEFINEnewAS(marker='X'))TORDERBYid
Tolerating Gaps Row Pattern Matching
Comments
SELECTid,markerFROMmsgMATCH_RECOGNIZE(ORDERBYidALLROWSPERMATCHPATTERN(new+(readnew+)*)DEFINEnewAS(marker='X'))TORDERBYid
Tolerating Gaps Row Pattern Matching
Comments
Repeat groupany numberof times
SELECTid,markerFROMmsgMATCH_RECOGNIZE(ORDERBYidALLROWSPERMATCHPATTERN(new+(readnew+)*)DEFINEnewAS(marker='X'))TORDERBYid
Tolerating Gaps Row Pattern Matching
Comments
Repeat groupany numberof times
SELECTid,markerFROMmsgMATCH_RECOGNIZE(ORDERBYidALLROWSPERMATCHPATTERN(new+(readnew+)*)DEFINEnewAS(marker='X'))TORDERBYid
Tolerating Gaps Row Pattern Matching
CommentsFirst match
SELECTid,markerFROMmsgMATCH_RECOGNIZE(ORDERBYidALLROWSPERMATCHPATTERN(new+(readnew+)*)DEFINEnewAS(marker='X'))TORDERBYid
Tolerating Gaps Row Pattern Matching
CommentsSecondmatch
SELECTid,markerFROMmsgMATCH_RECOGNIZE(ORDERBYidALLROWSPERMATCHPATTERN(new+(readnew+)*)DEFINEnewAS(marker='X'))TORDERBYid
Tolerating Gaps Row Pattern Matching
Comments
SELECTid,markerFROMmsgMATCH_RECOGNIZE(ORDERBYidALLROWSPERMATCHPATTERN((^read)?new+(readnew+)*(read$)?)DEFINEnewAS(marker='X'))TORDERBYthread_id,id
Tolerating Gaps (also first/last) Row Pattern Matching
CommentsWhat about
this?
SELECTid,markerFROMmsgMATCH_RECOGNIZE(ORDERBYidALLROWSPERMATCHPATTERN((^read)?new+(readnew+)*(read$)?)DEFINEnewAS(marker='X'))TORDERBYthread_id,id
Tolerating Gaps (also first/last) Row Pattern Matching
Comments
Match“read” at the very
beginning
SELECTid,markerFROMmsgMATCH_RECOGNIZE(ORDERBYidALLROWSPERMATCHPATTERN((^read)?new+(readnew+)*(read$)?)DEFINEnewAS(marker='X'))TORDERBYthread_id,id
Tolerating Gaps (also first/last) Row Pattern Matching
Comments
Optionally match“read” at the very
beginning
SELECTid,markerFROMmsgMATCH_RECOGNIZE(ORDERBYidALLROWSPERMATCHPATTERN((^read)?new+(readnew+)*(read$)?)DEFINEnewAS(marker='X'))TORDERBYthread_id,id
Tolerating Gaps (also first/last) Row Pattern Matching
Comments
SELECTt.*FROM(SELECTmsg.*,LAG(marker,1,'X')OVER(ORDERBYid)prev_marker,LEAD(marker,1,'X')OVER(ORDERBYid)next_markerFROMmsg)tWHEREmarker='X'OR(prev_marker='X'andnext_marker=‘X')ORDERBYid
Tolerating Gaps lead & lag
Comments
I don't care what anything was designed to do, I care about what it can do.
—Apollo 13, Universal Pictures
Tolerating Gaps (with grouped gaps) Row Pattern Matching
CommentsLoad 2 more Load 9 more
Tell me how many rows you skipped in between
SELECTid,marker,gap_lengthFROMmsgMATCH_RECOGNIZE(ORDERBYidMEASURESFINALCOUNT(more.*)ASgap_lengthALLROWSPERMATCHPATTERN((^read)?new+(readnew+)*(read$)?|more{-more*-})DEFINEnewAS(marker='X'),moreAS(marker!='X'))TORDERBYid
Tolerating Gaps (with grouped gaps) Row Pattern Matching
CommentsLoad 2 more Load 9 more
SELECTid,marker,gap_lengthFROMmsgMATCH_RECOGNIZE(ORDERBYidMEASURESFINALCOUNT(more.*)ASgap_lengthALLROWSPERMATCHPATTERN((^read)?new+(readnew+)*(read$)?|more{-more*-})DEFINEnewAS(marker='X'),moreAS(marker!='X'))TORDERBYid
Tolerating Gaps (with grouped gaps) Row Pattern Matching
CommentsLoad 2 more Load 9 more
AlternativeMatch, but don’t return
SELECTid,marker,gap_lengthFROMmsgMATCH_RECOGNIZE(ORDERBYidMEASURESFINALCOUNT(more.*)ASgap_lengthALLROWSPERMATCHPATTERN((^read)?new+(readnew+)*(read$)?|more{-more*-})DEFINEnewAS(marker='X'),moreAS(marker!='X'))TORDERBYid
Tolerating Gaps (with grouped gaps) Row Pattern Matching
CommentsLoad 2 more Load 9 more
Considerall rows
SELECTid,marker,gap_lengthFROMmsgMATCH_RECOGNIZE(ORDERBYidMEASURESFINALCOUNT(more.*)ASgap_lengthALLROWSPERMATCHPATTERN((^read)?new+(readnew+)*(read$)?|more{-more*-})DEFINEnewAS(marker='X'),moreAS(marker!='X'))TORDERBYid
Tolerating Gaps (with grouped gaps) Row Pattern Matching
CommentsLoad 2 more Load 9 moreOnly rows
matched to the pattern variable
“more”
SELECTid,marker,CASEWHENmarker!='X'ANDgap_length>2THENgap_lengthENDgap_lengthFROM(SELECTt2.*,COUNT(CASEWHENmarker!='X'THEN1END)OVER(PARTITIONBYnew_counter)gap_lengthFROM(SELECTmsg.*,COUNT(CASEWHENmarker='X'THEN1END)OVER(ORDERBYid)new_counter,LAG(marker,1,'X')OVER(ORDERBYid)prev_markerFROMmsg)t2)t3WHEREmarker='X'ORgap_length=1ORprev_marker='X'ORDERBYid
Start-of-group taggingTolerating Gaps (with grouped gaps)
Comments
Top-N Per Group
Example: List 3 most recent comments per topic
Three approaches:
‣ lateral sub-query (requires specific indexing)
‣ Row pattern matching (requires 12c)
‣ row_number() window function
Time
Topic 3Topic 2Topic 1
SELECT*FROMtMATCH_RECOGNIZE(PARTITIONBYtopicORDERBYvalMEASURESRUNNINGCOUNT(*)ASrnALLROWSPERMATCHPATTERN(^a{1,3})DEFINEaAS1=1)
Time
Topic 3Topic 2Topic 1
Top-N Per Group
per “topic” processing
SELECT*FROMtMATCH_RECOGNIZE(PARTITIONBYtopicORDERBYvalMEASURESRUNNINGCOUNT(*)ASrnALLROWSPERMATCHPATTERN(^a{1,3})DEFINEaAS1=1)
Time
Topic 3Topic 2Topic 1
Top-N Per Group
Consider rows up till current
row
SELECT*FROMtMATCH_RECOGNIZE(PARTITIONBYtopicORDERBYvalMEASURESRUNNINGCOUNT(*)ASrnALLROWSPERMATCHPATTERN(^a{1,3})DEFINEaAS1=1)
Time
Topic 3Topic 2Topic 1
Top-N Per Group
1, 2, or 3 times
SELECT*FROMtMATCH_RECOGNIZE(PARTITIONBYtopicORDERBYvalMEASURESRUNNINGCOUNT(*)ASrnALLROWSPERMATCHPATTERN(^a{1,3})DEFINEaAS1=1)
Time
Topic 3Topic 2Topic 1
Top-N Per Group
DEFINE is non-optional: Use dummy
SELECT*FROMtMATCH_RECOGNIZE(PARTITIONBYtopicORDERBYvalMEASURESRUNNINGCOUNT(*)ASrnALLROWSPERMATCHPATTERN(^a{1,3})DEFINEaAS1=1)
SELECT*FROM(SELECTt.*,ROW_NUMBER()OVER(PARTITIONBYtopicORDERBYval)rnFROMt)tWHERErn<=3
Time
Topic 3Topic 2Topic 1
Top-N Per Group
SELECT*FROMtMATCH_RECOGNIZE(PARTITIONBYtopicORDERBYvalMEASURESRUNNINGCOUNT(*)ASrnALLROWSPERMATCHPATTERN(^a+)DEFINEaAScount(*)<=3)
SELECT*FROM(SELECTt.*,ROW_NUMBER()OVER(PARTITIONBYtopicORDERBYval)rnFROMt)tWHERErn<=3
Time
Topic 3Topic 2Topic 1
Top-N Per Group
Always RUNNING semantic
Time Intervals (non-overlapping)
Example: Bookings are stored as [begin; end[ intervals
Two problems:
‣ Find free time-slots
‣ Close free time-slots
Time
Busy Busy Busy
Time
SELECT*FROMreservationsMATCH_RECOGNIZE(ORDERBYbeginMEASURESa.endASbegin,b.beginASendONEROWPERMATCHAFTERMATCHSKIPTObPATTERN(ab)DEFINEbASa.end<begin)
Time Intervals (non-overlapping)
Time
SELECT*FROMreservationsMATCH_RECOGNIZE(ORDERBYbeginMEASURESa.endASbegin,b.beginASendONEROWPERMATCHAFTERMATCHSKIPTObPATTERN(ab)DEFINEbASa.end<begin)
a bTime Intervals (non-overlapping)
Time
SELECT*FROMreservationsMATCH_RECOGNIZE(ORDERBYbeginMEASURESa.endASbegin,b.beginASendONEROWPERMATCHAFTERMATCHSKIPTObPATTERN(ab)DEFINEbASa.end<begin)
a bTime Intervals (non-overlapping)
Time
SELECT*FROMreservationsMATCH_RECOGNIZE(ORDERBYbeginMEASURESa.endASbegin,b.beginASendONEROWPERMATCHAFTERMATCHSKIPTObPATTERN(ab)DEFINEbASa.end<begin)
a bTime Intervals (non-overlapping)
SELECT*FROMreservationsMATCH_RECOGNIZE(ORDERBYbeginMEASURESa.endASbegin,b.beginASendONEROWPERMATCHAFTERMATCHSKIPTObPATTERN(ab)DEFINEbASa.end<begin)
a bTime Intervals (non-overlapping)
Time
SELECT*FROMreservationsMATCH_RECOGNIZE(ORDERBYbeginMEASURESa.endASbegin,b.beginASendONEROWPERMATCHAFTERMATCHSKIPTObPATTERN(ab)DEFINEbASa.end<begin)
a bTime Intervals (non-overlapping)
Time
SELECT*FROMreservationsMATCH_RECOGNIZE(ORDERBYbeginMEASURESa.endASbegin,b.beginASendONEROWPERMATCHAFTERMATCHSKIPTObPATTERN(ab)DEFINEbASa.end<begin)
a bTime Intervals (non-overlapping)
Time
Default is tocontinue AFTERlast matched row
SELECT*FROMreservationsMATCH_RECOGNIZE(ORDERBYbeginMEASURESa.endASbegin,b.beginASendONEROWPERMATCHAFTERMATCHSKIPTObPATTERN(ab)DEFINEbASa.end<begin)
Time Intervals (non-overlapping)
Time
SELECT*FROMreservationsMATCH_RECOGNIZE(ORDERBYbeginMEASURESa.endASbegin,b.beginASendONEROWPERMATCHAFTERMATCHSKIPTObPATTERN(ab)DEFINEbASa.end<begin)
Time Intervals (non-overlapping)
Time
a b
SELECT*FROMreservationsMATCH_RECOGNIZE(ORDERBYbeginMEASURESa.endASbegin,b.beginASendONEROWPERMATCHAFTERMATCHSKIPTObPATTERN(ab)DEFINEbASa.end<begin)
Time Intervals (non-overlapping)
a bTime
SELECT*FROMreservationsMATCH_RECOGNIZE(ORDERBYbeginMEASURESa.endASbegin,b.beginASendONEROWPERMATCHAFTERMATCHSKIPTObPATTERN(ab)DEFINEbASa.end<begin)
Time Intervals (non-overlapping)
Time
SELECT*FROMreservationsMATCH_RECOGNIZE(ORDERBYbeginMEASURESa.endASbegin,b.beginASendONEROWPERMATCHAFTERMATCHSKIPTObPATTERN(ab)DEFINEbASa.end<begin)
Time Intervals (non-overlapping)
Time
SELECT*FROMreservationsMATCH_RECOGNIZE(ORDERBYbeginMEASURESa.endASbegin,b.beginASendONEROWPERMATCHAFTERMATCHSKIPTObPATTERN(ab)DEFINEbASa.end<begin)
Time Intervals (non-overlapping)
Time
SELECT*FROM(SELECTendbegin,LEAD(begin)OVER(ORDERBYbegin)endFROMreservations)WHEREbegin<end
SELECTbbegin,eend,typeFROMreservationsMATCH_RECOGNIZE(ORDERBYbeginMEASURESCASEWHENfree.beginISNULLTHENbusy.beginELSEbusy.endENDASb,COALESCE(free.begin,busy.end)ASe,CLASSIFIER()astypeALLROWSPERMATCHAFTERMATCHSKIPTONEXTROWPATTERN(busyfree?)DEFINEfreeASbegin>PREV(end))
Row Pattern Matching
Time
Time Intervals (close gaps)
Always matchone row. Second only
if there is a gap
Busy Free
SELECTbbegin,eend,typeFROMreservationsMATCH_RECOGNIZE(ORDERBYbeginMEASURESCASEWHENfree.beginISNULLTHENbusy.beginELSEbusy.endENDASb,COALESCE(free.begin,busy.end)ASe,CLASSIFIER()astypeALLROWSPERMATCHAFTERMATCHSKIPTONEXTROWPATTERN(busyfree?)DEFINEfreeASbegin>PREV(end))
Row Pattern Matching
Time
Time Intervals (close gaps)
Busy Free
SELECTbbegin,eend,typeFROMreservationsMATCH_RECOGNIZE(ORDERBYbeginMEASURESCASEWHENfree.beginISNULLTHENbusy.beginELSEbusy.endENDASb,COALESCE(free.begin,busy.end)ASe,CLASSIFIER()astypeALLROWSPERMATCHAFTERMATCHSKIPTONEXTROWPATTERN(busyfree?)DEFINEfreeASbegin>PREV(end))
Row Pattern Matching
Time
Time Intervals (close gaps)
Busy FreeIf it is not a
“free” row, passrow through
SELECTbbegin,eend,typeFROMreservationsMATCH_RECOGNIZE(ORDERBYbeginMEASURESCASEWHENfree.beginISNULLTHENbusy.beginELSEbusy.endENDASb,COALESCE(free.begin,busy.end)ASe,CLASSIFIER()astypeALLROWSPERMATCHAFTERMATCHSKIPTONEXTROWPATTERN(busyfree?)DEFINEfreeASbegin>PREV(end))
Row Pattern MatchingTime Intervals (close gaps)
Busy FreeTime
SELECTbbegin,eend,typeFROMreservationsMATCH_RECOGNIZE(ORDERBYbeginMEASURESCASEWHENfree.beginISNULLTHENbusy.beginELSEbusy.endENDASb,COALESCE(free.begin,busy.end)ASe,CLASSIFIER()astypeALLROWSPERMATCHAFTERMATCHSKIPTONEXTROWPATTERN(busyfree?)DEFINEfreeASbegin>PREV(end))
Row Pattern MatchingTime Intervals (close gaps)
Busy FreeTime
Free
SELECTbbegin,eend,typeFROMreservationsMATCH_RECOGNIZE(ORDERBYbeginMEASURESCASEWHENfree.beginISNULLTHENbusy.beginELSEbusy.endENDASb,COALESCE(free.begin,busy.end)ASe,CLASSIFIER()astypeALLROWSPERMATCHAFTERMATCHSKIPTONEXTROWPATTERN(busyfree?)DEFINEfreeASbegin>PREV(end))
Row Pattern MatchingTime Intervals (close gaps)
Busy FreeTime
Free
SELECTbbegin,eend,typeFROMreservationsMATCH_RECOGNIZE(ORDERBYbeginMEASURESCASEWHENfree.beginISNULLTHENbusy.beginELSEbusy.endENDASb,COALESCE(free.begin,busy.end)ASe,CLASSIFIER()astypeALLROWSPERMATCHAFTERMATCHSKIPTONEXTROWPATTERN(busyfree?)DEFINEfreeASbegin>PREV(end))
Row Pattern MatchingTime Intervals (close gaps)
BusyTime
Free
SELECTbbegin,eend,typeFROMreservationsMATCH_RECOGNIZE(ORDERBYbeginMEASURESCASEWHENfree.beginISNULLTHENbusy.beginELSEbusy.endENDASb,COALESCE(free.begin,busy.end)ASe,CLASSIFIER()astypeALLROWSPERMATCHAFTERMATCHSKIPTONEXTROWPATTERN(busyfree?)DEFINEfreeASbegin>PREV(end))
Row Pattern MatchingTime Intervals (close gaps)
BusyTime
Busy FreeFree
SELECTbbegin,eend,typeFROMreservationsMATCH_RECOGNIZE(ORDERBYbeginMEASURESCASEWHENfree.beginISNULLTHENbusy.beginELSEbusy.endENDASb,COALESCE(free.begin,busy.end)ASe,CLASSIFIER()astypeALLROWSPERMATCHAFTERMATCHSKIPTONEXTROWPATTERN(busyfree?)DEFINEfreeASbegin>PREV(end))
Row Pattern MatchingTime Intervals (close gaps)
Busy Busy FreeFreeTime
Free
SELECTbbegin,eend,typeFROMreservationsMATCH_RECOGNIZE(ORDERBYbeginMEASURESCASEWHENfree.beginISNULLTHENbusy.beginELSEbusy.endENDASb,COALESCE(free.begin,busy.end)ASe,CLASSIFIER()astypeALLROWSPERMATCHAFTERMATCHSKIPTONEXTROWPATTERN(busyfree?)DEFINEfreeASbegin>PREV(end))
Row Pattern MatchingTime Intervals (close gaps)
Busy BusyFreeTime
Free Busy
SELECTbegin,end,typeFROM(SELECTendbegin,LEAD(begin)OVER(ORDERBYbegin)end,'FREE'typeFROMreservations)WHEREbegin<endUNIONALLSELECTbegin,end,'BUSY'typeFROMreservations
Busy BusyFreeTime
Free BusyTime Intervals (close gaps) Window function
Endless possibilitesRow Pattern Matching
GROUPBY➡ONEROWPERMATCH
OVER()➡ALLROWSPERMATCH,FINAL,RUNNINGHAVING,WHERE➡PATTERN (unmatched, suppressed {-…-})
Mixing GROUPBY and OVER()➡ALLROWSPERMATCH + all-but-one rows suppressed
Data-driven match length ➡ SUM, COUNT, … in DEFINE
Duplicating rows (to some extend)➡ ALLROWSPERMATCH + AFTERMATCHSKIPTO…
Not/Barely covered in this presentationRow Pattern Matching
‣ Reluctant (non-greedy) matching
‣ SHOW/OMITEMPTYMATCHESWITHUNMATCHEDROWS
‣ SUBSET (define pattern-vars for use in MEASURES,DEFINE and AFTERMATCHSKIPTO)
‣ PREV, NEXT, FIRST, LAST (with some nesting!)
‣MATCH_NUMBER()
Obstacles and Issues (as of 12r1)Row Pattern Matching
‣ JDBC !!!!!Tokens ?, {, } have special meaning in JDBC.You have to escape them using {\...\}https://docs.oracle.com/database/121/JJDBC/apxref.htm#CHECHCJH
‣ ORA-62513: Quantified subpatterns that can have empty matches are not yet supported
PATTERN(x(a*b*)+y)
‣ ORA-62512: This aggregate is not yet supported in MATCH_RECOGNIZE clause.(only COUNT, SUM, AVG, MIN, and MAX)
About @MarkusWinand
‣Training for Developers ‣ SQL Performance (Indexing) ‣ Modern SQL ‣ On-Site or Online
‣SQL Tuning ‣ Index-Redesign ‣ Query Improvements ‣ On-Site or Online
http://winand.at/
About @MarkusWinand
€0,-€10-30
‣Training for Developers ‣ SQL Performance (Indexing) ‣ Modern SQL ‣ On-Site or Online
‣SQL Tuning ‣ Index-Redesign ‣ Query Improvements ‣ On-Site or Online
sql-performance-explained.com
Recommended