Best regards, Stew

]]>Seems that your SQL has one or two typos in it, I assume

with n as ( select level as n from dual connect by level <= 200 ) ,f(b,f) as ( select 1 as b, 1 as f from dual union all select f, b+f from f where 2*b+f <= 200 ), candidates as ( select n.n, f.f from n, f where n.n >= f.f ) select n || ' = ' || listagg(f,' + ') within group(order by f desc) z_r from candidates match_recognize( partition by n order by f desc all rows per match pattern((A|{-B-})+) define A as sum(A.f) <= n ) group by n

was meant.

]]>1. Generate just enough fibonacci numbers to get to 200, by stopping when f(n) + f(n-2) is greater than 200

2. Join n and f such that f is never greater than n.

(The combination of 1. and 2. reduces the number of input rows from 6000 to 1836.)

3. Instead of running a subquery for each n, run one query using “partition by n” and “group by n”.

4. Instead of “where cls = ‘A'”, use the “exclusion syntax {- -}” in the PATTERN clause.

5. Without the WHERE clause, no need for the MEASURES clause.

with n as (

select level as n

from dual

connect by level <= 200

)

,f(b,f) as (

select 1 as b, 1 as f

from dual

union all

select f, b+f

from f

where 2*b+f = f

)

select n, listagg(f,’+’) within group(order by f desc) z_r

from candidates

match_recognize(

partition by n order by f desc

all rows per match

pattern((A|{-B-})+)

define A as sum(A.f) <= n

)

group by n;

To me, Oren's use of (A|B)* to implement the greedy algorithm was the fundamental insight that allowed for use of MATCH_RECOGNIZE. Hats off to you both!

]]>fantastic !

Didn’t know how cool pattern matching really can be !

Thanks Matthias

]]>This is really cool!

Encouraged by your post, I wrote another version of this query, using 12c Pattern Matching (with your “Fibonacci generator”).

The elapsed time (for the same population of the first 200 natural numbers) is now less than 0.1 second.

with

f(n, a, b) as

(

/* construct fibonaccis, 30 are surely enough … */

select 1 as n, 1 as a, 1 as b

from dual

union all

select n+1, b, a+b

from f

where n<=30

)

select n.n || ' = ' ||

(select listagg(f,' + ') within group (order by f desc)

from (select n.n,f.a as f from f)

match_recognize(

order by f desc

measures classifier() cls

all rows per match

pattern(A (A|B)*)

define A as sum(A.f) <= n)

where cls='A') zeckendorf_representation

from (select level as n from dual connect by level <= 200) n;

Thanks,

Oren.