Skip to content

Instantly share code, notes, and snippets.

@swanandp
Last active November 29, 2023 17:23

Revisions

  1. swanandp revised this gist Nov 29, 2023. 2 changed files with 0 additions and 0 deletions.
    File renamed without changes.
    File renamed without changes.
  2. swanandp revised this gist Nov 29, 2023. 1 changed file with 15 additions and 0 deletions.
    15 changes: 15 additions & 0 deletions how_does_it_work.md
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,15 @@
    # How does it work?

    The general format of a recursive query is:

    ```sql
    WITH RECURSIVE cte_name(arg1, arg2, arg3) AS( -- arg1, arg2 are column outputs from seed_data_query
    seed_data_query -- non-recursive term, executes first
    UNION ALL -- can be just UNION, which returns unique rows. It's slower.
    recursive_query_based_on_seed_data -- recursive term
    ) SELECT * FROM cte_name;
    ```
    When executing, the `seed_data_query` executes first, giving a set of base results. Note that this is not the "base case" from recursion. In recursion, base case is a terminating clause and is the last to execute. Here, the non-recursive part acts as seed data for the recursive part. Termination of a recursive CTE happens when the recursive part yields 0 rows.

    The result of `seed_data_query` is passed as argument to the next query. For `recursive_query_based_on_seed_data`, `cte_name(arg1, arg2, arg3)` is available as a temporary table with columns arg1, arg2, arg3, etc. All your regular join operations are possible with this temporary table.

  3. swanandp revised this gist Nov 29, 2023. 1 changed file with 1 addition and 1 deletion.
    2 changes: 1 addition & 1 deletion recurstive_cte.sql
    Original file line number Diff line number Diff line change
    @@ -5,7 +5,7 @@ CREATE TABLE posts
    reply_to_id bigint REFERENCES posts (id)
    );

    TRUNCATE posts RESTART IDENTITY; -- this deleted all rows and restarts the auto-increment ID
    TRUNCATE posts RESTART IDENTITY; -- this deletes all rows and restarts the auto-increment ID

    /*
    Let's create nested data like this:
  4. swanandp created this gist Nov 29, 2023.
    91 changes: 91 additions & 0 deletions recurstive_cte.sql
    Original file line number Diff line number Diff line change
    @@ -0,0 +1,91 @@
    CREATE TABLE posts
    (
    id bigserial PRIMARY KEY,
    content text NOT NULL,
    reply_to_id bigint REFERENCES posts (id)
    );

    TRUNCATE posts RESTART IDENTITY; -- this deleted all rows and restarts the auto-increment ID

    /*
    Let's create nested data like this:
    -> R
    -> R-O
    -> R-O-A
    -> R-O-A-D
    -> R-O-D
    -> R-A
    -> R-A-P
    -> S
    -> H
    */

    INSERT INTO posts(content)
    VALUES ('R');

    INSERT INTO posts(content, reply_to_id)
    VALUES ('RO', 1),
    ('RA', 1);

    INSERT INTO posts(content, reply_to_id)
    VALUES ('ROA', 2),
    ('RAP', 3);

    INSERT INTO posts(content, reply_to_id)
    VALUES ('ROAD', 4);

    INSERT INTO posts(content, reply_to_id)
    VALUES ('ROD', 2);

    INSERT INTO posts(content)
    VALUES ('S');

    INSERT INTO posts(content, reply_to_id)
    VALUES ('SH', 7);

    SELECT *
    FROM posts;


    -- select all children for 'R'
    WITH RECURSIVE leaves(id, content, reply_to_id) AS
    (SELECT id, content, reply_to_id
    FROM posts
    WHERE content = 'R'

    UNION ALL

    SELECT p.id, p.content, p.reply_to_id
    FROM leaves l
    INNER JOIN posts p ON l.id = p.reply_to_id)
    SELECT *
    FROM leaves;

    -- select all children for 'S'
    WITH RECURSIVE leaves(id, content, reply_to_id) AS
    (SELECT id, content, reply_to_id
    FROM posts
    WHERE content = 'S'

    UNION ALL

    SELECT p.id, p.content, p.reply_to_id
    FROM leaves l
    INNER JOIN posts p ON l.id = p.reply_to_id)
    SELECT *
    FROM leaves;

    -- select all children for 'RO'
    WITH RECURSIVE leaves(id, content, reply_to_id) AS
    (SELECT id, content, reply_to_id
    FROM posts
    WHERE content = 'RO'

    UNION ALL

    SELECT p.id, p.content, p.reply_to_id
    FROM leaves l
    INNER JOIN posts p ON l.id = p.reply_to_id)
    SELECT *
    FROM leaves;