Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    primarykey
    data
    text
    <p>You can't do recursion in SQL without stored procedures. The way to solve this is using Nested Sets, they basically model a tree in SQL as a set.</p> <p>Notice that this will require a change to the current data model or possibly figuring out how to create a view on the original model.</p> <p>Postgresql example (using very few postgresql extensions, just SERIAL and ON COMMIT DROP, most RDBMSes will have similar functionality):</p> <p>Setup:</p> <pre><code>CREATE TABLE objects( id SERIAL PRIMARY KEY, name TEXT, lft INT, rgt INT ); INSERT INTO objects(name, lft, rgt) VALUES('The root of the tree', 1, 2); </code></pre> <p>Adding a child:</p> <pre><code>START TRANSACTION; -- postgresql doesn't support variables so we create a temporary table that -- gets deleted after the transaction has finished. CREATE TEMP TABLE left_tmp( lft INT ) ON COMMIT DROP; -- not standard sql -- store the left of the parent for later use INSERT INTO left_tmp (lft) VALUES((SELECT lft FROM objects WHERE name = 'The parent of the newly inserted node')); -- move all the children already in the set to the right -- to make room for the new child UPDATE objects SET rgt = rgt + 2 WHERE rgt &gt; (SELECT lft FROM left_tmp LIMIT 1); UPDATE objects SET lft = lft + 2 WHERE lft &gt; (SELECT lft FROM left_tmp LIMIT 1); -- insert the new child INSERT INTO objects(name, lft, rgt) VALUES( 'The name of the newly inserted node', (SELECT lft + 1 FROM left_tmp LIMIT 1), (SELECT lft + 2 FROM left_tmp LIMIT 1) ); COMMIT; </code></pre> <p>Display a trail from bottom to top:</p> <pre><code>SELECT parent.id, parent.lft FROM objects AS current_node INNER JOIN objects AS parent ON current_node.lft BETWEEN parent.lft AND parent.rgt WHERE current_node.name = 'The name of the deepest child' ORDER BY parent.lft; </code></pre> <p>Display the entire tree:</p> <pre><code>SELECT REPEAT(' ', CAST((COUNT(parent.id) - 1) AS INT)) || '- ' || current_node.name AS indented_name FROM objects current_node INNER JOIN objects parent ON current_node.lft BETWEEN parent.lft AND parent.rgt GROUP BY current_node.name, current_node.lft ORDER BY current_node.lft; </code></pre> <p>Select everything down from a certain element of the tree:</p> <pre><code>SELECT current_node.name AS node_name FROM objects current_node INNER JOIN objects parent ON current_node.lft BETWEEN parent.lft AND parent.rgt AND parent.name = 'child' GROUP BY current_node.name, current_node.lft ORDER BY current_node.lft; </code></pre>
    singulars
    1. This table or related slice is empty.
    plurals
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. This table or related slice is empty.
    1. VO
      singulars
      1. This table or related slice is empty.
    2. VO
      singulars
      1. This table or related slice is empty.
    3. VO
      singulars
      1. This table or related slice is empty.
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload