Oracle FAQ Your Portal to the Oracle Knowledge Grid
HOME | ASK QUESTION | ADD INFO | SEARCH | E-MAIL US
 

Home -> Community -> Usenet -> comp.databases.theory -> Re: Nested set model with large gaps and spreads in the numbering

Re: Nested set model with large gaps and spreads in the numbering

From: John Gilson <jag_at_acm.org>
Date: Mon, 16 Sep 2002 20:47:48 GMT
Message-ID: <Urrh9.64759$c7.18055610@twister.nyc.rr.com>


The issue is to move the gaps between siblings in a tree to the right of the rightmost sibling while also maintaining the spread between each node's left and right values. Additionally, it would be useful to be able to set the root node's left value to 1 before left shifting so that the tree is put into "normal form". This would be useful if we wanted to present a subtree normalized. Furthermore, we might want to begin the left shifting at any node in the tree and not just the tree's root node. When working with a very large tree it could be much more efficient to left shift only certain subtrees, indicated by giving the subtree's root node.

Before we can left shift a tree we need to identify the gaps to close. There are two types of gaps:
1. Between the left value of the oldest, i.e., leftmost, child N1L and

   the left value of its parent N2L. We look for instances where    N1L - N2L > 1.
2. Between the left value of a node N1L and the right value of its

   sibling N2R to the immediate left. We look for instances where    N1L - N2R > 1.

For all gaps on level N to be closed, all gaps in the previous N-1 levels must have been closed. This would lead to a top-down breadth-first iterative algorithm. However, note that when left shifting a level N the same amount of shifting must be simultaneously applied to all descendants of this level so that the tree's ancestor-descendant relationship, represented by nested sets, is always maintained.

Below is some T-SQL code, tested on SQL Server, that implements this followed by a few examples. The code might appear a bit complex on a first pass but the algorithm is straightforward. Note that while iteration is used, no temp tables or extra columns are required.

First, let's show the DDL and sample data.

CREATE TABLE Tree
(
value VARCHAR(10) NOT NULL PRIMARY KEY,
lft INT NOT NULL CHECK (lft > 0),
rgt INT NOT NULL CHECK (rgt > 0),
CHECK (rgt > lft)
)

INSERT INTO TREE
SELECT 'Albert', 100, 1200
UNION ALL
SELECT 'Bert', 101, 201
UNION ALL
SELECT 'Ernie', 250, 300
UNION ALL
SELECT 'Chuck', 400, 1100
UNION ALL
SELECT 'Donna', 501, 601
UNION ALL
SELECT 'Eddie', 701, 801
UNION ALL
SELECT 'Fred', 901, 1001

Next, let's look at some views that provide structural information about the tree.

Finally, the stored procedure that does the left shifting.

  DECLARE @consecutiveSiblingGap INT
  SELECT @consecutiveSiblingGap = G.gap
  FROM ConsecutiveSiblingGaps AS G
  WHERE G.level = @currentLevel AND

        G.rgtChild = @node

  DECLARE @parentOldestChildGap INT
  SELECT @parentOldestChildGap = G.gap
  FROM ParentOldestChildGaps AS G
  WHERE G.childLevel = @currentLevel AND

        G.child = @node

  UPDATE Tree

  SET lft = COALESCE(Tree.lft - @consecutiveSiblingGap,
                     Tree.lft - @parentOldestChildGap,
                     Tree.lft),
      rgt = COALESCE(Tree.rgt - @consecutiveSiblingGap,
                     Tree.rgt - @parentOldestChildGap,
                     Tree.rgt)
  WHERE Tree.value = @node OR
        EXISTS (SELECT *
                FROM Descendants
                WHERE ancestor = @node AND
                      descendant = Tree.value)
END END Some examples might be illustrative. The tree we start with is

value lft rgt
Albert 100 1200
Bert 101 201
Ernie 250 300
Chuck 400 1100
Donna 501 601
Eddie 701 801
Fred 901 1001

If we want to left shift the entire tree we execute

EXEC ShiftLeft

so the resulting tree is

value lft rgt
Albert 100 1200
Bert 101 201
Ernie 202 252
Chuck 253 953
Donna 254 354
Eddie 355 455
Fred 456 556

If we want to shift the entire tree but start with a left value of 1 for the root node we execute

EXEC ShiftLeft 1

which results in the following tree

value lft rgt
Albert 1 1101
Bert 2 102
Ernie 103 153
Chuck 154 854
Donna 155 255
Eddie 256 356
Fred 357 457

Finally, we can just shift a subtree by giving that subtree's root node by executing

EXEC ShiftLeftSubtree 'Chuck'

which modifies the original table to

value lft rgt
Albert 100 1200
Bert 101 201
Ernie 250 300
Chuck 301 1001
Donna 302 402
Eddie 403 503
Fred 504 604

or

EXEC ShiftLeftSubtree 'Eddie'

value lft rgt
Albert 100 1200
Bert 101 201
Ernie 250 300
Chuck 400 1100
Donna 501 601
Eddie 602 702
Fred 901 1001

Regards,
jag Received on Mon Sep 16 2002 - 15:47:48 CDT

Original text of this message

HOME | ASK QUESTION | ADD INFO | SEARCH | E-MAIL US