Skip to Main Content

Breadcrumb

Question and Answer

Chris Saxon

Thanks for the question, Rajeshwaran.

Asked: January 08, 2016 - 3:44 pm UTC

Last updated: June 28, 2022 - 12:41 pm UTC

Version: 12.1.0.2

Viewed 10K+ times! This question is

You Asked

some where after OOW, i got this deck "12c_PatternMatching_CON9101_Laker-SQL - the best development language for Big Data.ppt" downloaded, but dont know if it is still available for download.

Slide no 43 has an example for SQL Pattern matching example for "Suspicious Money Transfers"

set feedback off
drop table t purge;
create table t(tstmp date, user_id varchar2(10),event varchar2(20),amt int);
insert into t values(to_date('01-Jan-2012','dd-mon-yyyy') ,'John','Deposit',1000000);
insert into t values(to_date('02-Jan-2012','dd-mon-yyyy') ,'John','Transfer',1000);
insert into t values(to_date('05-Jan-2012','dd-mon-yyyy') ,'John','Withdrawal',2000);
insert into t values(to_date('10-Jan-2012','dd-mon-yyyy') ,'John','Transfer',1500);
insert into t values(to_date('20-Jan-2012','dd-mon-yyyy') ,'John','Transfer',1200);
insert into t values(to_date('25-Jan-2012','dd-mon-yyyy') ,'John','Deposit',1200000);
insert into t values(to_date('27-Jan-2012','dd-mon-yyyy') ,'John','Transfer',1000000);
insert into t values(to_date('02-Feb-2012','dd-mon-yyyy') ,'John ','Deposit',500000);
commit;
set feedback on

<Requirment>
Detect suspicious money transfer pattern for an account
Three or more small amount (<1K) money transfers within 30 days
Subsequent large transfer (>=1M) within 10 days of last small transfer.
Report account, date of first small transfer, date of last large transfer
</Requirment>

Here is the query from that slide to handle this requirement.

SELECT *
FROM t MATCH_RECOGNIZE 
( PARTITION BY user_id 
 ORDER BY tstmp
 measures     
   first(x.tstmp) first_t, 
         y.tstmp last_t, 
   y.amt amts
 PATTERN ( (; X ) {3,} Y )   
 DEFINE X AS (event = 'Transfer' AND amt < 1000 AND
                     last(X.tstmp) - first(X.tstmp) < 30)           
       Y AS (event = 'Transfer' AND amt > 1000000 AND
                     y.tstmp - last(x.tstmp) < 10 ) ) 


but when i run this it gave me this error. could you help me with resolving this error ?

rajesh@ORA12C>
rajesh@ORA12C> SELECT *
  2  FROM t MATCH_RECOGNIZE
  3  ( PARTITION BY user_id
  4     ORDER BY tstmp
  5     measures
  6              first(x.tstmp) first_t,
  7           y.tstmp last_t,
  8              y.amt amts
  9     PATTERN ( (; X ) {3,} Y )
 10     DEFINE X AS (event = 'Transfer' AND amt < 1000 AND
 11                       last(X.tstmp) - first(X.tstmp) < 30)
 12         Y AS (event = 'Transfer' AND amt > 1000000 AND
 13                       y.tstmp - last(x.tstmp) < 10 ) )
 14  /
        PATTERN ( (; X ) {3,} Y )
                   *
ERROR at line 9:
ORA-00931: missing identifier


rajesh@ORA12C>

and Chris said...

Remove the semi-colon before the X and put a comma after the definition of the Y variable:

SELECT *
FROM t MATCH_RECOGNIZE 
( PARTITION BY user_id 
    ORDER BY tstmp
    measures              
         first(x.tstmp) first_t, 
         y.tstmp last_t, 
         y.amt amts
    PATTERN ( ( X ) {3,} Y )         
    DEFINE X AS (event = 'Transfer' AND amt < 1000 AND
                     last(X.tstmp) - first(X.tstmp) < 30) ,         
       Y AS (event = 'Transfer' AND amt > 1000000 AND
                     y.tstmp - last(x.tstmp) < 10 ) ) 

Rating

  (8 ratings)

Is this answer out of date? If it is, please let us know via a Comment

Comments

with new data sets

Rajeshwaran, Jeyabal, January 09, 2016 - 11:24 am UTC

Would you help us to achieve this requirement using SQL Pattern matching ? tried with myself but not success.

<Requirment>
Detect suspicious money transfer pattern for an account
a) Three or more small amount (<1K) money transfers within 30 days
b) Subsequent large transfer (>=1M) within 10 days of last small transfer.
Report account, date of first small transfer, date of last large transfer
</Requirment>

set feedback off 
drop table t purge; 
create table t(tstmp date, user_id varchar2(10),event varchar2(20),amt int); 
insert into t values(to_date('01-Jan-2012','dd-mon-yyyy') ,'John','Deposit',1000000); 
insert into t values(to_date('02-Jan-2012','dd-mon-yyyy') ,'John','Transfer',950); 
insert into t values(to_date('05-Jan-2012','dd-mon-yyyy') ,'John','Withdrawal',2000); 
insert into t values(to_date('10-Jan-2012','dd-mon-yyyy') ,'John','Transfer',800); 
insert into t values(to_date('20-Jan-2012','dd-mon-yyyy') ,'John','Transfer',700); 
insert into t values(to_date('25-Jan-2012','dd-mon-yyyy') ,'John','Deposit',1200000); 
insert into t values(to_date('27-Jan-2012','dd-mon-yyyy') ,'John','Transfer',1000000); 
insert into t values(to_date('02-Feb-2012','dd-mon-yyyy') ,'John ','Deposit',500000); 
commit; 
set feedback on 


rajesh@ORA12C> select * from t order by tstmp;

TSTMP       USER_ID    EVENT                       AMT
----------- ---------- -------------------- ----------
01-JAN-2012 John       Deposit                 1000000
02-JAN-2012 John       Transfer                    950  << 1st Transfer 
05-JAN-2012 John       Withdrawal                 2000
10-JAN-2012 John       Transfer                    800 << 2nd Transfer < 1K and within 30 days 
20-JAN-2012 John       Transfer                    700  << 3rd Transfer < 1K and within 30 days
25-JAN-2012 John       Deposit                 1200000
27-JAN-2012 John       Transfer                1000000  << large transfer >1M within 10 day of last transfer
02-FEB-2012 John       Deposit                  500000

8 rows selected.

rajesh@ORA12C>  


rajesh@ORA12C> SELECT *
  2  FROM t MATCH_RECOGNIZE
  3  ( PARTITION BY user_id
  4      ORDER BY tstmp
  5      measures
  6           first(x.tstmp) first_t,
  7           y.tstmp last_t,
  8           y.amt amts
  9      PATTERN ( ( X ) {3,} Y )
 10      DEFINE X AS (event = 'Transfer' AND amt < 1000 AND
 11                       last(X.tstmp) - first(X.tstmp) < 30) ,
 12         Y AS (event = 'Transfer' AND amt > 1000000 AND
 13                       y.tstmp - last(x.tstmp) < 10 ) )
 14  /

no rows selected

rajesh@ORA12C>

Connor McDonald
January 10, 2016 - 4:44 am UTC

SQL> SELECT *
  2      FROM ( select * from t where event = 'Transfer' )
  3      MATCH_RECOGNIZE
  4      ( PARTITION BY user_id
  5          ORDER BY tstmp
  6          measures
  7               first(x.tstmp) first_t,
  8               last(x.tstmp) last_t,
  9               y.tstmp y_last_t,
 10               y.amt amts
 11          PATTERN ( X{3,} Y )
 12         DEFINE X AS (event = 'Transfer' AND amt < 1000 AND last(X.tstmp) - first(X.tstmp) < 30) ,
 13                Y AS (event = 'Transfer' AND amt >= 1000000 AND y.tstmp - last(x.tstmp) < 10 )
 14            )
 15     /

USER_ID    FIRST_T   LAST_T    Y_LAST_T        AMTS
---------- --------- --------- --------- ----------
John       02-JAN-12 20-JAN-12 27-JAN-12    1000000


The changes being:

1) restrict the potential candidates to only Transfers
2) Change the ">" to ">=" for Y

Empty matches

Rajeshwaran Jeyabal, August 30, 2016 - 3:12 pm UTC

Re-reading the doc again.

http://docs.oracle.com/database/121/DWHSG/pattern.htm#DWHSG8984

....
The MATCH_RECOGNIZE clause may find a match with zero rows. For an empty match, ONE ROW PER MATCH returns a summary row:
the PARTITION BY columns take the values from the row where the empty match occurs, 
and the measure columns are evaluated over an empty set of rows
....


( The DDL's and DML's for the "Ticker" table is available in the above documentation link )

demo@ORA12C> select * from ticker
  2  match_recognize(
  3    partition by symbol
  4    order by tstamp
  5    measures
  6      count(price) as cnt,
  7      sum(price) as tot_price
  8    one row per match
  9    pattern ( strt down+)
 10    define
 11      down as price > prev(price) and price > 5000 )
 12  /

no rows selected

demo@ORA12C>


Incase of an empty match i don't see an "Summary row" getting returned - is that i am missing something here ?
Chris Saxon
August 30, 2016 - 3:48 pm UTC

You're not seeing an empty match because there isn't one!

down+


says "find one or more rows for down". So to match there must be at least one row. Thus you can't have an "empty match"!

If you change the + to a *, this means "find zero or more rows". This produces empty matches:

select * from ticker
match_recognize(
  partition by symbol
  order by tstamp
  measures
    count(price) as cnt,
    sum(price) as tot_price,
    classifier() as cls
 one row per match
  pattern ( down*)
  define
   down as price > prev(price) and price > 5000 )
/

SYMBOL  CNT  TOT_PRICE  CLS  
ACME    0                    
ACME    0                    
ACME    0                    
ACME    0                    
ACME    0                    
ACME    0                    
ACME    0                    
ACME    0                    
ACME    0                    
ACME    0                    
ACME    0                    
ACME    0                    
ACME    0                    
ACME    0                    
ACME    0                    
ACME    0                    
ACME    0                    
ACME    0                    
ACME    0                    
ACME    0   

Debugging MATCH_RECOGNIZE

Duke Ganote, August 31, 2016 - 4:08 pm UTC

"ALL ROWS PER MATCH WITH UNMATCHED ROWS", CLASSIFIER, and MATCH_NUMBER are handy for debugging MATCH_RECOGNIZE.

WITH 
   ticked (SYMBOL,  tstamp    , price) AS (              SELECT
           'ACME', '01-Apr-11', 12   FROM DUAL UNION ALL SELECT
           'ACME', '02-Apr-11', 17   FROM DUAL UNION ALL SELECT
           'ACME', '03-Apr-11', 19   FROM DUAL UNION ALL SELECT
           'ACME', '04-Apr-11', 21   FROM DUAL UNION ALL SELECT
           'ACME', '05-Apr-11', 25   FROM DUAL UNION ALL SELECT
           'ACME', '06-Apr-11', 12   FROM DUAL UNION ALL SELECT
           'ACME', '07-Apr-11', 15   FROM DUAL UNION ALL SELECT
           'ACME', '08-Apr-11', 20   FROM DUAL UNION ALL SELECT
           'ACME', '09-Apr-11', 24   FROM DUAL UNION ALL SELECT
           'ACME', '10-Apr-11', 25   FROM DUAL UNION ALL SELECT
           'ACME', '11-Apr-11', 19   FROM DUAL UNION ALL SELECT
           'ACME', '12-Apr-11', 15   FROM DUAL UNION ALL SELECT
           'ACME', '13-Apr-11', 25   FROM DUAL UNION ALL SELECT
           'ACME', '14-Apr-11', 25   FROM DUAL UNION ALL SELECT
           'ACME', '15-Apr-11', 14   FROM DUAL UNION ALL SELECT
           'ACME', '16-Apr-11', 12   FROM DUAL UNION ALL SELECT
           'ACME', '17-Apr-11', 14   FROM DUAL UNION ALL SELECT
           'ACME', '18-Apr-11', 24   FROM DUAL UNION ALL SELECT
           'ACME', '19-Apr-11', 23   FROM DUAL UNION ALL SELECT
           'ACME', '20-Apr-11', 22   FROM DUAL 
), 
ticker AS (
 select symbol, to_date(tstamp,'DD-MON-YY') tstamp, price
   from ticked
)
select * from ticker
   match_recognize(
     partition by symbol
     order by tstamp
     measures
       count(price)    as cnt,
       sum(price)      as tot_price,
       MATCH_NUMBER()  AS "MATCH_NUMBER()",
       CLASSIFIER()    AS "CLASSIFIER()"
ALL ROWS PER MATCH WITH UNMATCHED ROWS
     pattern ( strt down*)
     define
       down as price > prev(price) and price > 5000 );

SYMB TSTAMP               CNT  TOT_PRICE MATCH_NUMBER() CLASSIFIER()    PRICE
---- ------------------- ---- ---------- -------------- ------------ --------
ACME 2011-04-01 00:00:00    1         12              1 STRT               12
ACME 2011-04-02 00:00:00    1         17              2 STRT               17
ACME 2011-04-03 00:00:00    1         19              3 STRT               19
ACME 2011-04-04 00:00:00    1         21              4 STRT               21
ACME 2011-04-05 00:00:00    1         25              5 STRT               25
ACME 2011-04-06 00:00:00    1         12              6 STRT               12
ACME 2011-04-07 00:00:00    1         15              7 STRT               15
ACME 2011-04-08 00:00:00    1         20              8 STRT               20
ACME 2011-04-09 00:00:00    1         24              9 STRT               24
ACME 2011-04-10 00:00:00    1         25             10 STRT               25
ACME 2011-04-11 00:00:00    1         19             11 STRT               19
ACME 2011-04-12 00:00:00    1         15             12 STRT               15
ACME 2011-04-13 00:00:00    1         25             13 STRT               25
ACME 2011-04-14 00:00:00    1         25             14 STRT               25
ACME 2011-04-15 00:00:00    1         14             15 STRT               14
ACME 2011-04-16 00:00:00    1         12             16 STRT               12
ACME 2011-04-17 00:00:00    1         14             17 STRT               14
ACME 2011-04-18 00:00:00    1         24             18 STRT               24
ACME 2011-04-19 00:00:00    1         23             19 STRT               23
ACME 2011-04-20 00:00:00    1         22             20 STRT               22

20 rows selected.

Chris Saxon
September 01, 2016 - 3:21 am UTC

nice work!

layers of match_recognize

Rajeshwaran Jeyabal, September 12, 2016 - 2:11 pm UTC

http://docs.oracle.com/database/121/DWHSG/pattern.htm#DWHSG9026

...
Note that it is not prohibited to feed the output of one MATCH_RECOGNIZE clause into the input of another
...

but i did this, it is working for me, did i missing something here?

demo@ORA12C> select *
  2  from (
  3  select * from emp
  4  match_recognize(
  5    partition by deptno
  6    order by sal
  7    measures
  8      match_number() mno,
  9      classifier() cls,
 10      sum(sal) tot_sal
 11    one row per match
 12    pattern( strt down* )
 13    define
 14      down as prev(sal) <= sal)
 15      )
 16  match_recognize(
 17    partition by deptno
 18    order by tot_sal,mno
 19    measures
 20      match_number() mno2,
 21      count(*) as cnt
 22    all rows per match
 23    pattern( strt down*)
 24    define
 25      down as prev(tot_sal) <= tot_sal)
 26  /

    DEPTNO    TOT_SAL        MNO       MNO2        CNT CLS
---------- ---------- ---------- ---------- ---------- ----------
        10       8750          1          1          1 DOWN
        20      10875          1          1          1 DOWN
        30       9400          1          1          1 DOWN

3 rows selected.

demo@ORA12C> set autotrace traceonly explain
demo@ORA12C> select *
  2  from (
  3  select * from emp
  4  match_recognize(
  5    partition by deptno
  6    order by sal
  7    measures
  8      match_number() mno,
  9      classifier() cls,
 10      sum(sal) tot_sal
 11    one row per match
 12    pattern( strt down* )
 13    define
 14      down as prev(sal) <= sal)
 15      )
 16  match_recognize(
 17    partition by deptno
 18    order by tot_sal,mno
 19    measures
 20      match_number() mno2,
 21      count(*) as cnt
 22    all rows per match
 23    pattern( strt down*)
 24    define
 25      down as prev(tot_sal) <= tot_sal)
 26  /

Execution Plan
----------------------------------------------------------
Plan hash value: 39797153

-----------------------------------------------------------------------------------------------------------------
| Id  | Operation                                                | Name | Rows  | Bytes | Cost (%CPU)| Time     |
-----------------------------------------------------------------------------------------------------------------
|   0 | SELECT STATEMENT                                         |      |    14 |  1148 |     5  (40)| 00:00:01 |
|   1 |  VIEW                                                    |      |    14 |  1148 |     5  (40)| 00:00:01 |
|   2 |   MATCH RECOGNIZE SORT DETERMINISTIC FINITE AUTOMATON    |      |    14 |   784 |     5  (40)| 00:00:01 |
|   3 |    VIEW                                                  |      |    14 |   784 |     4  (25)| 00:00:01 |
|   4 |     VIEW                                                 |      |    14 |   784 |     4  (25)| 00:00:01 |
|   5 |      BUFFER SORT                                         |      |    14 |    98 |     4  (25)| 00:00:01 |
|   6 |       MATCH RECOGNIZE SORT DETERMINISTIC FINITE AUTOMATON|      |    14 |    98 |     4  (25)| 00:00:01 |
|   7 |        TABLE ACCESS FULL                                 | EMP  |    14 |    98 |     3   (0)| 00:00:01 |
-----------------------------------------------------------------------------------------------------------------

demo@ORA12C> set autotrace off
demo@ORA12C>

Chris Saxon
September 12, 2016 - 4:39 pm UTC

I don't understand what the issue is. The double negative does make hard reading, but:

Note that it is not prohibited => you are allowed to.

You're allowed to chain them like you have done.

Is this a bug in match recognize?

Rajeshwaran, Jeyabal, June 24, 2022 - 6:00 am UTC

demo@XEPDB1> variable x varchar2(10)
demo@XEPDB1> exec :x := '20371229';

PL/SQL procedure successfully completed.

demo@XEPDB1> select *
  2  from (
  3  select to_date(:x,'yyyymmdd')-1+rownum as dt
  4  from dual
  5  connect by level <= 10 )
  6  match_recognize(
  7     order by dt
  8     measures
  9             match_number() mno,
 10             classifier() cls,
 11             count(*) as cnt,
 12             first(dt) as start_range,
 13             last(dt) as end_range
 14     pattern (a b+)
 15     define
 16             b as dt = prev(dt)+1 );

       MNO CLS               CNT START_RANGE END_RANGE
---------- ---------- ---------- ----------- -----------
         1 B                  10 29-DEC-2037 07-JAN-2038

demo@XEPDB1> variable x varchar2(10)
demo@XEPDB1> exec :x := '20471229';

PL/SQL procedure successfully completed.

demo@XEPDB1> select *
  2  from (
  3  select to_date(:x,'yyyymmdd')-1+rownum as dt
  4  from dual
  5  connect by level <= 10 )
  6  match_recognize(
  7     order by dt
  8     measures
  9             match_number() mno,
 10             classifier() cls,
 11             count(*) as cnt,
 12             first(dt) as start_range,
 13             last(dt) as end_range
 14     pattern (a b+)
 15     define
 16             b as dt = prev(dt)+1 ) ;

       MNO CLS               CNT START_RANGE END_RANGE
---------- ---------- ---------- ----------- -----------
         1 B                   7 01-JAN-2048 07-JAN-2048
         2 B                   3 29-DEC-2047 31-DEC-2047

demo@XEPDB1>


Questions:
1) why all these data was not part of a single match when the input is "20471229" ? why two matches here?
2) why the match_number = 1 is for 01-Jan-2048 instead of 29-dec-2047 ?

Chris Saxon
June 24, 2022 - 10:05 am UTC

There's certainly something fishy going on here. If you expand it to include ALL ROWS PER MATCH, you can see the 2048 dates are appearing before the 2047 dates:

variable x varchar2(10)
exec :x := '20471229';

select *
from (
  select to_date(:x,'yyyymmdd')-1+rownum as dt
  from dual
  connect by level <= 10 
)
match_recognize (
   order by dt
   measures
     match_number() mno,
     classifier() cls,
     count(*) as cnt,
     first(dt) as start_range,
     last(dt) as end_range
   all rows per match
   pattern (a b+)
   define
           b as dt = prev(dt)+1 
);

DT               MNO CLS               CNT START_RAN END_RANGE
--------- ---------- ---------- ---------- --------- ---------
01-JAN-48          1 A                   1 01-JAN-48 01-JAN-48
02-JAN-48          1 B                   2 01-JAN-48 02-JAN-48
03-JAN-48          1 B                   3 01-JAN-48 03-JAN-48
04-JAN-48          1 B                   4 01-JAN-48 04-JAN-48
05-JAN-48          1 B                   5 01-JAN-48 05-JAN-48
06-JAN-48          1 B                   6 01-JAN-48 06-JAN-48
07-JAN-48          1 B                   7 01-JAN-48 07-JAN-48
29-DEC-47          2 A                   1 29-DEC-47 29-DEC-47
30-DEC-47          2 B                   2 29-DEC-47 30-DEC-47
31-DEC-47          2 B                   3 29-DEC-47 31-DEC-47


Is this a problem for you? Have you raised it with support?

Is this a bug in match recognize?

Rajeshwaran, Jeyabal, June 24, 2022 - 11:20 am UTC

yes could see the same on my 21c(XE) database - 2048 were appearing before 2047 - sorry dont have access to support, hence raising this up.

demo@XEPDB1> variable x varchar2(10)
demo@XEPDB1> exec :x := '20471229';

PL/SQL procedure successfully completed.

demo@XEPDB1>
demo@XEPDB1> select *
  2  from (
  3    select to_date(:x,'yyyymmdd')-1+rownum as dt
  4    from dual
  5    connect by level <= 10
  6  )
  7  match_recognize (
  8     order by dt
  9     measures
 10       match_number() mno,
 11       classifier() cls,
 12       count(*) as cnt,
 13       first(dt) as start_range,
 14       last(dt) as end_range
 15     all rows per match
 16     pattern (a b+)
 17     define
 18             b as dt = prev(dt)+1
 19  );

DT                 MNO CLS               CNT START_RANGE END_RANGE
----------- ---------- ---------- ---------- ----------- -----------
01-JAN-2048          1 A                   1 01-JAN-2048 01-JAN-2048
02-JAN-2048          1 B                   2 01-JAN-2048 02-JAN-2048
03-JAN-2048          1 B                   3 01-JAN-2048 03-JAN-2048
04-JAN-2048          1 B                   4 01-JAN-2048 04-JAN-2048
05-JAN-2048          1 B                   5 01-JAN-2048 05-JAN-2048
06-JAN-2048          1 B                   6 01-JAN-2048 06-JAN-2048
07-JAN-2048          1 B                   7 01-JAN-2048 07-JAN-2048
29-DEC-2047          2 A                   1 29-DEC-2047 29-DEC-2047
30-DEC-2047          2 B                   2 29-DEC-2047 30-DEC-2047
31-DEC-2047          2 B                   3 29-DEC-2047 31-DEC-2047

10 rows selected.

Chris Saxon
June 28, 2022 - 12:41 pm UTC

OK, I'll raise a bug for this

date12 vs date13

Iintern Al, June 27, 2022 - 2:27 pm UTC

2048 were appearing before 2047

This is a bug of internal date format:
variable x varchar2(10)
exec :x := '20471229'
select 'date expr' ty, dump(to_date(:x,'yyyymmdd')) du from dual union all
select 'date date', dump(cast(to_date(:x,'yyyymmdd') as date)) from dual;

TY        DU                                 
--------- -----------------------------------
date expr Typ=13 Len=8: 255,7,12,29,0,0,0,0  
date date Typ=12 Len=7: 120,147,12,29,1,1,1  


Use an explicit cast or a real column of the table.
Chris Saxon
June 28, 2022 - 12:41 pm UTC

Good analysis, thanks

date12 vs date13

Another example, June 27, 2022 - 3:22 pm UTC

create table t1 as
select date '2047-12-29' + level d from dual connect by level<=4;

select d, dump(d) d12, dump(d+0) d13 from t1 order by d;

D          D12                                 D13                                
---------- ----------------------------------- -----------------------------------
2047-12-30 Typ=12 Len=7: 120,147,12,30,1,1,1   Typ=13 Len=8: 255,7,12,30,0,0,0,0  
2047-12-31 Typ=12 Len=7: 120,147,12,31,1,1,1   Typ=13 Len=8: 255,7,12,31,0,0,0,0  
2048-01-01 Typ=12 Len=7: 120,148,1,1,1,1,1     Typ=13 Len=8: 0,8,1,1,0,0,0,0      
2048-01-02 Typ=12 Len=7: 120,148,1,2,1,1,1     Typ=13 Len=8: 0,8,1,2,0,0,0,0      

drop table t1 purge;


More to Explore

Analytics

Analytic SQL got you confused? Check out Connor McDonald's complete video course.