Skip to content

Instantly share code, notes, and snippets.

@kentoj
Forked from emmanuel/file.sql
Last active December 31, 2021 07:12
Show Gist options
  • Save kentoj/872cbefc68f68a2a97b6189da9cd6e23 to your computer and use it in GitHub Desktop.
Save kentoj/872cbefc68f68a2a97b6189da9cd6e23 to your computer and use it in GitHub Desktop.
Closure Table operations SQL fragments
-- Retrieve descendants
-- ====================
-- retrieve descendants of #4
SELECT c.*
FROM Comments AS c
JOIN TreePaths AS t ON c.comment_id = t.descendant
WHERE t.ancestor = 4;
-- Retrieve ancestors
-- ==================
-- retrieve ancestors of #6
SELECT c.*
FROM Comments AS c
JOIN TreePaths AS t ON c.comment_id = t.ancestor
WHERE t.descendant = 6;
-- Insert Leaf node
-- ================
-- insert leaf node #8 as a child of #5
INSERT INTO TreePaths (ancestor, descendant, path_length)
SELECT t.ancestor, 8, t.path_length + 1
FROM TreePaths AS t
WHERE t.descendant = 5
UNION ALL
SELECT 8, 8;
-- Delete Leaf node
-- ================
-- delete leaf node #7
DELETE FROM TreePaths WHERE descendant = 7;
-- Delete Subtree
-- ==============
-- delete #4 and all children from the tree
DELETE FROM TreePaths
WHERE descendant IN (SELECT descendant
FROM TreePaths
WHERE ancestor = 4);
-- Move Subtree (2 steps)
-- ============
-- reparent #6 from #4 -> #3
--
-- Step 1: Disconnect from current ancestors
-- -----------------------------------------
-- delete all paths that end at descendants in the current node's subtree
-- and that begin at ancestors of the current node (6).
DELETE FROM TreePaths
WHERE descendant IN (SELECT descendant
FROM TreePaths
WHERE ancestor = 6)
AND ancestor IN (SELECT ancestor
FROM TreePaths
WHERE descendant = 6
AND ancestor != descendant);
-- Step 2: Insert rows matching ancestors of insertion point and descendants of subtree
-- ------------------------------------------------------------------------------------
-- This uses CROSS JOIN to get the cross product of the new parent's ancestors, including the new parent,
-- with the subtree's nodes. This is one case where the full cartesian product is useful.
INSERT INTO TreePaths (ancestor, descendant, path_length)
SELECT
supertree.ancestor,
subtree.descendant,
supertree.path_length + subtree.path_length + 1 AS path_length
FROM TreePaths AS supertree
CROSS JOIN TreePaths AS subtree
WHERE supertree.descendant = 3
AND subtree.ancestor = 6;
@djoyrocks
Copy link

Hi How to get all the root nodes ?
A
B
C
D
E
F

Result: A, D, E

@chibyk101
Copy link

chibyk101 commented Apr 18, 2021

how is the 1st root node inserted?
lets say the very 1st comment which doesn't have a parent comment or ancestor, what's the initial depth?

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