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: Wed, 18 Sep 2002 21:19:14 GMT
Message-ID: <m56i9.3934$GJ3.730335@twister.nyc.rr.com>


"--CELKO--" <71062.1056_at_compuserve.com> wrote in message news:c0d87ec0.0209170539.7ce7653a_at_posting.google.com...

> >> For some reason, what you are trying to do reminds me of the
> process of
> defragmenting a disk. <<
>
> Good thought!
>
> Richard Romley sent me a recursive UDF that computes the new left
> value for a node.  It can be put into one statement then used in
>   UPDATE Tree
>      SET lft = ShiftLeft(left),
>          rgt = ShiftLeft(left) + (rgt-lft);
>
> Very neat.  I have to go out of town, but I will post it when I get
> back.

Actually, it's possible to write a single view, with a few supporting views for clarity, that can calculate the total amount every node in the tree needs to be shifted, relative to some reference node, to move all gaps rightward. The algorithm is as follows:

forall(Paths P with head node H and tail node T where H = T or T is a

       descendant of H, have T be the node whose shift amount will be
       calculated with respect to the reference node H)
begin
  headNodeLevel := Level(H)
  tailNodeLevel := Level(T)
  forall(Nodes N where Level(N) >= headNodeLevel and
         Level(N) <= tailNodeLevel and
         PN is the node at Level(N) within Path P and
         N's lft value is <= PN's lft value)
  begin
    The total shift amount of T with respect to H is     sum(ConsecutiveSiblingGap of N) + sum(ParentOldestChildGap of N)   end
end

The translation of this to SQL is

With the helping views defined as

The procedure to actually shift the tree is now very straightforward and succinct

CREATE PROCEDURE ShiftLeftHelper
@node VARCHAR(10) -- reference node of tree or subtree to begin shifting AS
BEGIN   UPDATE Tree
  SET lft = Tree.lft - (SELECT gap

                        FROM ShiftedLeftValues
                        WHERE rootNode = @node AND
                              shiftNode = Tree.value),
      rgt = Tree.rgt - (SELECT gap
                        FROM ShiftedLeftValues
                        WHERE rootNode = @node AND
                              shiftNode = Tree.value)
  WHERE (SELECT gap
         FROM ShiftedLeftValues
         WHERE rootNode = @node AND
               shiftNode = Tree.value) > 0

END -- PROCEDURE

This will produce the same results as my other algorithm. It would be interesting to evaluate the performance of these two approaches, especially on large trees.

Let's look at a couple of examples.

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', 111, 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

To shift the entire tree

EXEC ShiftLeft

Tree becomes

value lft rgt
Albert 100 1200
Bert 101 191
Ernie 192 242
Chuck 243 943
Donna 244 344
Eddie 345 445
Fred 446 546

and to shift a subtree, for example,

EXEC ShiftLeftSubtree 'Chuck'

Tree becomes

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

Regards,
jag Received on Wed Sep 18 2002 - 16:19:14 CDT

Original text of this message

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