Upgrade to Pro — share decks privately, control downloads, hide ads and more …

Pattern Matching + SQL Macros

Chris
June 01, 2020

Pattern Matching + SQL Macros

How to use match_recognize with SQL macros to create reusable SQL fragments

You can get the scripts for the SQL examples in Live SQL:

https://livesql.oracle.com/apex/livesql/file/content_KPBT70LOJM9EIEWT5WWQTMXRN.html
https://livesql.oracle.com/apex/livesql/file/content_KPC7JMI7AXP22YR76GWPFITCT.html

Chris

June 01, 2020
Tweet

More Decks by Chris

Other Decks in Technology

Transcript

  1. Your SQL Office Hours begins soon… SQL Pattern Matching +

    SQL Macros Chris Saxon @ChrisRSaxon & @SQLDaily https://www.youtube.com/c/TheMagicofSQL https://blogs.oracle.com/sql
  2. The following is intended to outline our general product direction.

    It is intended for information purposes only, and may not be incorporated into any contract. It is not a commitment to deliver any material, code, or functionality, and should not be relied upon in making purchasing decisions. The development, release, timing, and pricing of any features or functionality described for Oracle’s products may change and remains at the sole discretion of Oracle Corporation. Statements in this presentation relating to Oracle’s future plans, expectations, beliefs, intentions and prospects are “forward-looking statements” and are subject to material risks and uncertainties. A detailed discussion of these factors and other risks that affect our business is contained in Oracle’s Securities and Exchange Commission (SEC) filings, including our most recent reports on Form 10-K and Form 10-Q under the heading “Risk Factors.” These filings are available on the SEC’s website or on Oracle’s website at http://www.oracle.com/investor. All information in this presentation is current as of September 2020 and Oracle undertakes no duty to update any statement in light of new information or future events. Safe Harbor Copyright © 2020 Oracle and/or its affiliates.
  3. RUN_DATE TIME_IN_S DISTANCE_IN_KM 01 Apr 2020 310 1 02 Apr

    2020 1,600 5 03 Apr 2020 3,580 11 06 Apr 2020 1,550 5 07 Apr 2020 300 1 10 Apr 2020 280 1 13 Apr 2020 1,530 5 14 Apr 2020 295 1 15 Apr 2020 292 1
  4. RUN_DATE TIME_IN_S DISTANCE_IN_KM 01 Apr 2020 310 1 02 Apr

    2020 1,600 5 03 Apr 2020 3,580 11 06 Apr 2020 1,550 5 07 Apr 2020 300 1 10 Apr 2020 280 1 13 Apr 2020 1,530 5 14 Apr 2020 295 1 15 Apr 2020 292 1 #1 #3 #2 #4
  5. RUN_DATE TIME_IN_S DISTANCE_IN_KM 01 Apr 2020 310 1 02 Apr

    2020 1,600 5 03 Apr 2020 3,580 11 06 Apr 2020 1,550 5 07 Apr 2020 300 1 10 Apr 2020 280 1 13 Apr 2020 1,530 5 14 Apr 2020 295 1 15 Apr 2020 292 1 this = prev + 1
  6. RUN_DATE TIME_IN_S DISTANCE_IN_KM 01 Apr 2020 310 1 02 Apr

    2020 1,600 5 03 Apr 2020 3,580 11 06 Apr 2020 1,550 5 07 Apr 2020 300 1 10 Apr 2020 280 1 13 Apr 2020 1,530 5 14 Apr 2020 295 1 15 Apr 2020 292 1 this = prev + 1 this = prev + 3
  7. RUN_DATE TIME_IN_S DISTANCE_IN_KM 01 Apr 2020 310 1 02 Apr

    2020 1,600 5 03 Apr 2020 3,580 11 06 Apr 2020 1,550 5 07 Apr 2020 300 1 10 Apr 2020 280 1 13 Apr 2020 1,530 5 14 Apr 2020 295 1 15 Apr 2020 292 1 this = prev + 1 this = prev + 3 this ≠ prev + 1
  8. pattern ( init consecutive* ) define consecutive as run_date =

    prev ( run_date ) + 1 Undefined => "Always true" > 0 matches
  9. RUN_DATE VARIABLE TIME_IN_S DISTANCE_IN_KM 01 Apr 2020 INIT 310 1

    02 Apr 2020 CONSECUTIVE 1,600 5 03 Apr 2020 CONSECUTIVE 3,580 11 06 Apr 2020 INIT 1,550 5 07 Apr 2020 CONSECUTIVE 300 1 10 Apr 2020 INIT 280 1 13 Apr 2020 INIT 1,530 5 14 Apr 2020 CONSECUTIVE 295 1 15 Apr 2020 CONSECUTIVE 292 1
  10. pattern ( init consecutive* ) define consecutive as run_date =

    prev ( run_date ) + 1 Which row is prev?!
  11. match_recognize ( order by run_date measures first ( run_date )

    as start_date, count (*) as days pattern ( init consecutive* ) define consecutive as run_date = prev ( run_date ) + 1 ); How many consecutive rows? First row in group
  12. open cur for 'select * from ' || tab ||

    ' match_recognize ( … ); SQL
  13. Copyright © 2020, Oracle and/or its affiliates. All rights reserved.

    | blogs.oracle.com/sql www.youtube.com/c/TheMagicOfSQL @ChrisRSaxon SQL Macros table scalar
  14. Copyright © 2020, Oracle and/or its affiliates. All rights reserved.

    | blogs.oracle.com/sql www.youtube.com/c/TheMagicOfSQL @ChrisRSaxon SQL Macros table scalar in from clause "everywhere" else
  15. Copyright © 2020, Oracle and/or its affiliates. All rights reserved.

    | blogs.oracle.com/sql www.youtube.com/c/TheMagicOfSQL @ChrisRSaxon SQL Macros table scalar in from clause "everywhere" else only these in 19.6
  16. Copyright © 2020, Oracle and/or its affiliates. All rights reserved.

    | blogs.oracle.com/sql www.youtube.com/c/TheMagicOfSQL @ChrisRSaxon create function top_n ( num_rows number, tab dbms_tf.table_t ) return varchar2 sql_macro is begin select * from top_n.tab fetch first top_n.num_rows rows only
  17. Copyright © 2020, Oracle and/or its affiliates. All rights reserved.

    | blogs.oracle.com/sql www.youtube.com/c/TheMagicOfSQL @ChrisRSaxon create function top_n ( num_rows number, tab dbms_tf.table_t ) return varchar2 sql_macro is begin return 'select * from top_n.tab fetch first top_n.num_rows rows only'; end;
  18. Copyright © 2020, Oracle and/or its affiliates. All rights reserved.

    | blogs.oracle.com/sql www.youtube.com/c/TheMagicOfSQL @ChrisRSaxon create function top_n ( num_rows number, tab dbms_tf.table_t ) return varchar2 sql_macro is begin return 'select * from top_n.tab fetch first top_n.num_rows rows only'; end;
  19. Copyright © 2020, Oracle and/or its affiliates. All rights reserved.

    | blogs.oracle.com/sql www.youtube.com/c/TheMagicOfSQL @ChrisRSaxon create function top_n ( num_rows number, tab dbms_tf.table_t ) return varchar2 sql_macro is begin return 'select * from top_n.tab fetch first top_n.num_rows rows only'; end; Find/replace
  20. Copyright © 2020, Oracle and/or its affiliates. All rights reserved.

    | blogs.oracle.com/sql www.youtube.com/c/TheMagicOfSQL @ChrisRSaxon from top_n ( 5, employees ) from top_n ( :bind, jobs ) (19.6) from employees fetch first 5 rows only from jobs fetch first :bind rows only
  21. Copyright © 2020, Oracle and/or its affiliates. All rights reserved.

    | blogs.oracle.com/sql www.youtube.com/c/TheMagicOfSQL @ChrisRSaxon from top_n ( 5, employees ) from top_n ( :bind, jobs ) (19.6) from employees fetch first 5 rows only from jobs fetch first :bind rows only
  22. Copyright © 2020, Oracle and/or its affiliates. All rights reserved.

    | blogs.oracle.com/sql www.youtube.com/c/TheMagicOfSQL @ChrisRSaxon from top_n ( 5, employees ) from top_n ( :bind, jobs ) (19.6) from employees fetch first 5 rows only from jobs fetch first :bind rows only
  23. Copyright © 2020, Oracle and/or its affiliates. All rights reserved.

    | blogs.oracle.com/sql www.youtube.com/c/TheMagicOfSQL @ChrisRSaxon create function get_consecutive_rows ( tab dbms_tf.table_t, col dbms_tf.columns_t ) return varchar2 sql_macro is begin return 'get_consecutive_rows.tab match_recognize ( … )'; end;
  24. Copyright © 2020, Oracle and/or its affiliates. All rights reserved.

    | Person 09:00 10:00 11:00 12:00 13:00 14:00 15:00 16:00 1 2 Find the gap
  25. Copyright © 2020, Oracle and/or its affiliates. All rights reserved.

    | Person 09:00 10:00 11:00 12:00 13:00 14:00 15:00 16:00 1 2 Find the gap [ start, end ) >= 09:00 < 12:00
  26. Copyright © 2020, Oracle and/or its affiliates. All rights reserved.

    | Person Start Time End Time Running Max 1 09:00 10:00 2 09:00 12:00 1 10:00 10:30 1 11:00 13:00 2 12:30 13:00 2 13:00 14:00 2 15:00 17:00 1 16:00 17:00
  27. Copyright © 2020, Oracle and/or its affiliates. All rights reserved.

    | Person Start Time End Time Running Max 1 09:00 10:00 10:00 2 09:00 12:00 1 10:00 10:30 1 11:00 13:00 2 12:30 13:00 2 13:00 14:00 2 15:00 17:00 1 16:00 17:00
  28. Copyright © 2020, Oracle and/or its affiliates. All rights reserved.

    | Person Start Time End Time Running Max 1 09:00 10:00 10:00 2 09:00 12:00 12:00 1 10:00 10:30 1 11:00 13:00 2 12:30 13:00 2 13:00 14:00 2 15:00 17:00 1 16:00 17:00
  29. Copyright © 2020, Oracle and/or its affiliates. All rights reserved.

    | Person Start Time End Time Running Max 1 09:00 10:00 10:00 2 09:00 12:00 12:00 1 10:00 10:30 12:00 1 11:00 13:00 2 12:30 13:00 2 13:00 14:00 2 15:00 17:00 1 16:00 17:00
  30. Copyright © 2020, Oracle and/or its affiliates. All rights reserved.

    | Person Start Time End Time Running Max 1 09:00 10:00 10:00 2 09:00 12:00 12:00 1 10:00 10:30 12:00 1 11:00 13:00 13:00 2 12:30 13:00 13:00 2 13:00 14:00 14:00 2 15:00 17:00 1 16:00 17:00
  31. match_recognize ( order by start_date, end_date measures max ( end_date

    ) as start_date, next ( start_date ) as end_date all rows per match pattern ( ( gap | {-no_gap-} )+ ) define gap as max ( end_date ) < next ( start_date ) );
  32. match_recognize ( order by start_date, end_date measures max ( end_date

    ) as start_date, next ( start_date ) as end_date all rows per match pattern ( ( gap | {-no_gap-} )+ ) define gap as max ( end_date ) < next ( start_date ) ); {- exclude from output -}
  33. match_recognize ( order by start_date, end_date measures max ( end_date

    ) as start_date, next ( start_date ) as end_date all rows per match pattern ( ( gap | {-no_gap-} )+ ) define gap as max ( end_date ) < next ( start_date ) );
  34. match_recognize ( order by start_date, end_date measures max ( end_date

    ) as start_date, next ( start_date ) as end_date all rows per match pattern ( ( gap | {-no_gap-} )+ ) define gap as max ( end_date ) < next ( start_date ) );
  35. Copyright © 2020, Oracle and/or its affiliates. All rights reserved.

    | blogs.oracle.com/sql www.youtube.com/c/TheMagicOfSQL @ChrisRSaxon create function find_gaps ( tab dbms_tf.table_t, date_cols dbms_tf.columns_t ) return varchar2 sql_macro is begin return 'find_gaps.tab match_recognize ( … )'; end;
  36. Copyright © 2020, Oracle and/or its affiliates. All rights reserved.

    | SQL for date ranges, gaps and overlaps https://stewashton.wordpress.com/2014/03/11/sql- for-date-ranges-gaps-and-overlaps/ Oracle 20c: SQL Macros https://blog.sqlora.com/en/oracle-20c-sql-macros/ Further Reading
  37. Copyright © 2020, Oracle and/or its affiliates. All rights reserved.

    | asktom.oracle.com #MakeDataGreatAgain Ryan McGuire / Gratisography