Home > Blockchain >  SQLite Recursive Function
SQLite Recursive Function

Time:11-01

I have a view in SQLite where two columns need to follow a recursive formula. Example input data is below:

Date Ca Cb Cc
2020-01-01 NULL NULL 100.0
2020-01-02 0.1 NULL NULL
2020-01-03 0.2 NULL NULL
2020-01-04 0.1 NULL NULL
2020-01-05 0.4 NULL NULL
2020-01-06 0.3 NULL NULL
2020-01-07 0.2 NULL NULL
2020-01-08 0.4 NULL NULL
CREATE TABLE "Test" (
    "Date"  DATE,
    "Ca"    NUMERIC,
    "Cb"    NUMERIC,
    "Cc"    NUMERIC
);

INSERT INTO Test (Date, Ca, Cb, Cc)
VALUES ( '2020-01-01',  NULL, NULL, 100.0),
( '2020-01-02', 0.1, NULL, NULL),
( '2020-01-03', 0.2 , NULL, NULL),
( '2020-01-04', 0.1 ,  NULL, NULL),
( '2020-01-05', 0.4 , NULL, NULL),
( '2020-01-06', 0.3 , NULL, NULL),
( '2020-01-07', 0.2 , NULL, NULL),
( '2020-01-08', 0.4 , NULL, NULL)
;

The requirement is for columns [Cb] and [Cc] to be recursive such that (in rough SQL logic):

  • [Cb] = LAG([Cc]) * [Ca]
  • [Cc] = LAG([Cc]) [Cb]

So the second cell in column [Cb] would be equal to 10 or 100 * 0.1 and the second cell in [Cc] would be equal to 110 or 100 10.

The full solution, for this example, would look like this:

Date Ca Cb Cc
2020-01-01 NULL NULL 100.0
2020-01-02 0.1 10.0 110.0
2020-01-03 0.2 22.0 132.0
2020-01-04 0.1 13.2 145.2
2020-01-05 0.4 58.1 203.3
2020-01-06 0.3 61.0 264.3
2020-01-07 0.2 52.9 317.1
2020-01-08 0.4 126.8 444.0

The length of the table is dynamic, so the recursive solution must be dynamic as well.

I have read through and explored SQLite's recursive CTE feature, but I can't seem to figure out how to apply this in the context of a view. Or it is possible I should be approaching this problem differently. Any help or guidance would be greatly appreciated.

CodePudding user response:

In this context, there is no difference between a view and a table. First, I add row_number, so that it is straightforward to select the next row in the rCTE. Then you can calculate your target:

WITH RECURSIVE
    numbered AS (
        SELECT row_number() OVER (ORDER BY "Date") AS idx, * FROM Test
    ),
    new_test AS (
            SELECT * FROM numbered WHERE idx = 1
        UNION ALL
            SELECT
                numbered.idx,
                numbered."Date",
                numbered.Ca,
                new_test.Cc * numbered.Ca AS Cb,
                new_test.Cc   new_test.Cc * numbered.Ca AS Cc
            FROM new_test, numbered
            WHERE numbered.idx = new_test.idx   1
    )
SELECT "Date", Ca, round(Cb, 1) AS Cb, round(Cc, 1) AS Cc FROM new_test
  • Related