Skip to content

Instantly share code, notes, and snippets.

@seisvelas
Created July 30, 2019 21:30
Show Gist options
  • Star 1 You must be signed in to star a gist
  • Fork 0 You must be signed in to fork a gist
  • Save seisvelas/d60f5f2caf232dceede0326169014418 to your computer and use it in GitHub Desktop.
Save seisvelas/d60f5f2caf232dceede0326169014418 to your computer and use it in GitHub Desktop.
Recursive Fibonacci sequence up to nth number in SQL
WITH RECURSIVE fib (a, b, n) AS (
SELECT 0, 1, 1
UNION ALL
SELECT b, a+b, n+1 FROM fib
)
SELECT a FROM fib WHERE n<=8;
@seisvelas
Copy link
Author

Eso hice con WITH RECURSIVE porque soy demasiado pendejo hacerlo bien con una función :)

@A1rPun
Copy link

A1rPun commented Sep 11, 2019

Challenge!

Create a function in SQL or PL/SQL that accepts a number which represents the Nth Fibonacci number you want to output (and bonus points for all previous numbers).

Example

SELECT fib(6);

Output

fib
8

OR

Nth Fibonacci
0 0
1 1
2 1
3 2
4 3
5 5
6 8

etc.

@A1rPun
Copy link

A1rPun commented Sep 11, 2019

Alright it wasn't so hard after all in plpgsql. No bonus points for me though.

CREATE OR REPLACE FUNCTION fib(n INTEGER) RETURNS INTEGER AS $$
BEGIN
  IF (n < 2) THEN
    RETURN n;
  END IF;
  RETURN fib(n - 1) + fib(n - 2);
END;
$$ LANGUAGE plpgsql;

CREATE OR REPLACE FUNCTION fibLinear(n INTEGER) RETURNS INTEGER AS $$
DECLARE
  prevFib INTEGER := 0;
  fib INTEGER := 1;
BEGIN
  IF (n < 2) THEN
    RETURN n;
  END IF;

  WHILE n > 1 LOOP
    SELECT fib, prevFib + fib INTO prevFib, fib;
    n := n - 1;
  END LOOP;

  RETURN fib;
END;
$$ LANGUAGE plpgsql;

CREATE OR REPLACE FUNCTION fibFormula(n INTEGER) RETURNS INTEGER AS $$
BEGIN
  RETURN round(pow((pow(5, .5) + 1) / 2, n) / pow(5, .5));
END;
$$ LANGUAGE plpgsql;
select fib(6);

Output

 fib 
-----
   8

@seisvelas
Copy link
Author

seisvelas commented Sep 12, 2019

Wow I really need to learn plpgsql. Nevertheless, I think doing it with plpgsql misses most of the fun - which is forcing your brain to think in SQL's declarative paradigm! I know how to solve most simple algorithmic problems imperatively, and even functionally, but with declarative SQL? It's like learning to program all over again.

Plus, declarative programming can be surprisingly elegant for certain classes of problems.

@A1rPun
Copy link

A1rPun commented Sep 12, 2019

Yes you are right, there is no fun in imperative functions.. I'll try to create something declarative then 😄 (based off your gists)

@A1rPun
Copy link

A1rPun commented Sep 12, 2019

Current snippet causes an error

$ psql -f fib.sql 
psql:fib.sql:6: ERROR:  integer out of range

Kluged it by

WITH RECURSIVE fib (a, b, n) AS (
    SELECT 0, 1, 0
  UNION ALL
    SELECT b, a+b, n+1 FROM fib WHERE n < 45 -- Integer out of range kluge
)
SELECT n AS nth, a AS fibonacci FROM fib WHERE n<=8;

Outputs

 nth | fibonacci 
-----+-----------
   0 |         0
   1 |         1
   2 |         1
   3 |         2
   4 |         3
   5 |         5
   6 |         8
   7 |        13
   8 |        21
(9 rows)

TIL Recursion in SQL is just iteration

@seisvelas
Copy link
Author

TIL Recursion in SQL is just iteration

Consider what 'recursion' means in old-school Von Neumann style computer science. All iteration, including recursion, is just a bunch of GOTOs. This is how assembly works to this day. All loops are just conditional JMP instructions. Recursion (in assembly) just saves your current stack pointer and then puts the stack pointer somewhere fresh, runs some code, then jumps back to where it was (and restores the old stack pointer!). So recursion in this model is just a special approach to iteration.

If this is the meaning of recursion you have in mind, then SQL recursion is basically not recursion. The values aren't being pushed onto any stack, no stack-frames are being saved or new contexts created or anything like that. So in that sense, this is just normal iteration. (on the other hand, you COULD implement SQL recursion that way - it's just that SQL has tail call optimization for all recursion by definition, so why would you?)

However, if by recursion you mean in the symbolic / mathematical way of thinking about the term as a self-referential function, and we take the liberty of considering "SELECTing a value from a table" to roughly equate to "calling a function given a value" (with the table representing the function, the value representing...the value, and SELECT to represent calling the function) then SQL style recursion is very much normal recursion.

In the sense that a function just expresses a 1:1 x->y table of values, SQL's approach is almost 'purer' than the normal f(x)=f(x) type representation of recursion. After all, a table of inputs and outputs is every bit as valid as a representation of a function as the (irl less common) algebraic notation f(x).

@A1rPun
Copy link

A1rPun commented Sep 13, 2019

Fair enough, all functions drill down to some clever JMP instructions. What boggles my mind is that the "body" of the recursive CTE where the UNION ALL is iterating the result does not care about it's outer scope wanting to have just n<=8 results. I feel like the base case is missing. There is no returning of a value, it is iterating till infinity.

Don't get me wrong I'm convinced this is a recursive pattern and I enjoyed reading your comment!

@A1rPun
Copy link

A1rPun commented Sep 13, 2019

Here is another implementation I made today in plpgsql, tail recursion:

CREATE OR REPLACE FUNCTION fibTailRecursive(n INTEGER, prevFib INTEGER DEFAULT 0, fib INTEGER DEFAULT 1)
RETURNS INTEGER AS $$
BEGIN
  IF (n = 0) THEN
    RETURN prevFib;
  END IF;
  RETURN fibTailRecursive(n - 1, fib, prevFib + fib);
END;
$$ LANGUAGE plpgsql;

@seisvelas
Copy link
Author

When I was coding my solution in TablePlus it DID notice that it's outer scope only cares about n=8. That's why it ran forever for you but not for me. TablePlus is smart about that stuff. But I see what you mean, haha.

Recursion has sort of come under the dominion of functional programming, and this is a clearly non-functional approach to recursion. Do you have Hangouts? I'd love to chat more. It warms my heart to see people pursuing curiosity and intellectual gratification.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment