Advanced SQL: Row Pattern Matching (MATCH_RECOGNIZE)
Finding patterns across consecutive rows used to require complex self-joins or slow procedural loops. With MATCH_RECOGNIZE, you can search for trends, detect anomalies, and sessionize data using regular expressions directly in SQL.
1. Why We Need Pattern Matching
Imagine you have a table of daily stock prices or retail sales. You are tasked with finding a "V-Shape" recovery: a pattern where sales drop for three consecutive days, and then immediately rise for three consecutive days.
Historically, solving this in SQL was a nightmare. You would need multiple layers of LAG() and LEAD() window functions, complex self-joins, or you would simply give up and write a procedural PL/SQL loop.
In Oracle 12c, the ISO SQL standard MATCH_RECOGNIZE clause was introduced. It allows you to search for sequences of rows matching a specific condition using Regular Expressions.
2. The Anatomy of MATCH_RECOGNIZE
The MATCH_RECOGNIZE clause sits directly after the FROM or JOIN clause. It processes the data in a pipeline.
Understanding the Clauses
- PARTITION BY / ORDER BY: Just like window functions, you must define the boundaries (partition) and chronological sequence (order) of the data stream.
- PATTERN: The heart of the query. You assign arbitrary variable names (e.g.,
STRT,DOWN,UP) and use regex quantifiers:*(0 or more times)+(1 or more times)?(0 or 1 time){n,m}(between n and m times)
- DEFINE: Here you map the arbitrary variables to logical conditions.
PREV()lets you look at the previous row. - MEASURES: What to SELECT when a match is found.
3. Real-World Retail Use Cases
Use Case 1: Detecting Inventory Stockouts
Find instances where an item's inventory dropped below zero, stayed negative for at least two days, and then recovered to positive.
Use Case 2: Sessionization (Web Analytics)
In e-commerce, a "session" is a series of clicks by a user. If a user is inactive for more than 30 minutes, a new session begins.
MATCH_NUMBER()
The built-in MATCH_NUMBER() function sequentially assigns an ID to every pattern matched. It is incredibly useful for grouping rows into discrete sessions or events.
Use Case 3: Finding Missing Sequence Gaps
If you have a sequence of invoice numbers and want to find where numbers were skipped.


