Management of trees per performance intervallaire PDF Print E-mail
User Rating: / 0
PoorBest 
Saturday, 07 June 2008
Preamble
Here is a tree whose data represents families of vehicles:

1. Representation classic self-jointed
A usual way to represent such a tree is to provide an auto-join the table on itself:
CREATE TABLE FAMILLE
(FAM_ID INTEGER,
FAM_LIB VARCHAR(16),
FAM_PERE INTEGER)
INSERT INTO FAMILY (FAM_ID, FAM_LIB, FAM_PERE) VALUES (0, 'Transport', NULL)
INSERT INTO FAMILY (FAM_ID, FAM_LIB, FAM_PERE) VALUES (1, 'Terrestrial', 0)
INSERT INTO FAMILY (FAM_ID, FAM_LIB, FAM_PERE) VALUES (2, 'Marin', 0)
INSERT INTO FAMILY (FAM_ID, FAM_LIB, FAM_PERE) VALUES (3, 'Air', 0)
INSERT INTO FAMILY (FAM_ID, FAM_LIB, FAM_PERE) VALUES (4, 'Cars', 1)
INSERT INTO FAMILY (FAM_ID, FAM_LIB, FAM_PERE) VALUES (5, 'Truck', 1)
INSERT INTO FAMILY (FAM_ID, FAM_LIB, FAM_PERE) VALUES (6, 'Moto', 1)
INSERT INTO FAMILY (FAM_ID, FAM_LIB, FAM_PERE) VALUES (7, 'Cycling', 1)
INSERT INTO FAMILY (FAM_ID, FAM_LIB, FAM_PERE) VALUES (8, 'Helico', 3)
INSERT INTO FAMILY (FAM_ID, FAM_LIB, FAM_PERE) VALUES (9, 'Airplane', 3)
INSERT INTO FAMILY (FAM_ID, FAM_LIB, FAM_PERE) VALUES (10, 'ultralight', 3)
INSERT INTO FAMILY (FAM_ID, FAM_LIB, FAM_PERE) VALUES (11, 'Rocket', 3)
INSERT INTO FAMILY (FAM_ID, FAM_LIB, FAM_PERE) VALUES (12, 'Parachute', 3)
INSERT INTO FAMILY (FAM_ID, FAM_LIB, FAM_PERE) VALUES (13, 'glider', 3)
INSERT INTO FAMILY (FAM_ID, FAM_LIB, FAM_PERE) VALUES (14, 'Sailing', 2)
INSERT INTO FAMILY (FAM_ID, FAM_LIB, FAM_PERE) VALUES (15, 'Liner', 2)
INSERT INTO FAMILY (FAM_ID, FAM_LIB, FAM_PERE) VALUES (16, 'Plate Sailing', 2)
INSERT INTO FAMILY (FAM_ID, FAM_LIB, FAM_PERE) VALUES (17, 'Trail', 6)
INSERT INTO FAMILY (FAM_ID, FAM_LIB, FAM_PERE) VALUES (18, 'Side-car', 6)
INSERT INTO FAMILY (FAM_ID, FAM_LIB, FAM_PERE) VALUES (19, 'Civil', 9)
INSERT INTO FAMILY (FAM_ID, FAM_LIB, FAM_PERE) VALUES (20, 'Tourism', 9)
INSERT INTO FAMILY (FAM_ID, FAM_LIB, FAM_PERE) VALUES (21, 'Military', 9)

Here is the column that allows FAM_PERE join the element of the tree to its ancetre.
Finding the supervisor of an element is not something difficult. Take for example the Parachute (ID = 12); searching for the father made a complaint:
SELECT * FROM FAMILLE WHERE FAM_ID = (SELECT FAM_PERE FROM FAMILLE WHERE FAM_ID = 12)
FAM_ID      FAM_LIB          FAM_PERE 
----------- ---------------- -----------
3 Aerien 0

But finding all ascending is another pair of race. In general it goes through a recursive procedure such as:
Procedure RecherchePeres (in id integer, inout answer string)

begin
   reponse = reponse + ', ' + (SELECT FAM_LIB
                               FROM FAMILLE
                               WHERE FAM_ID = ID)
if id = 0
then
   return
else
   id = (SELECT FAM_PERE
         FROM FAMILLE
         WHERE FAM_ID = ID)
end

Now, not only recursion is very expensive, but some languages stored procedures, as Transact SQL Server Microsoft SQL do not manage it!

That is why this model is a proscire when:
     * The tree is deep (more than 5 levels)
     * The tree is large (over 100 items on the same level)
     * The tree contains a lot of values (from 200 to 300 items)
     * The majority of complaints are requests for interrogation - SELECT (at least 50% of requests)

And personally I advise you to spend the interval model whenever one of these 4 criteria is true!

2. Representation of the tree structure intervallaire
A particularly elegant way to represent powerful hierarchies type of tree is set up adjacent intervals and covering. The principle is simple:

     * Sheets located at the same level have adjacent intervals
     * Nodes covering of leaves or other nodes have intervals covering

Remember also that an interval consists of two values: low base and the base high.
We then said everything on this hierarchical representation ... But what is their interest?
If the insertion or deletion in such a representation is an inexpensive, interrogation and including research expressed mostly in a single request, as we shall see ...
For this model, we must assign at all entrances of our table tree the two terminals of the interval that we call BG (Borne Left) and BD (Borne Right). The allocation of values of these terminals being along the tree as if we drew a line for the closest circle without ever crossing that line with a branch and numbering sequentially each leaf or node for the first time by the left edge and a second time by the right edge (or by analogy with a sheet on the front and back) is on track around the tree line wrapping it in more just like this:

Of this figure, we can already see that:

     * The number of assigned number is double the number of elements
     * All the leaves have a long interval 1 (Point right - simply left = 1)
     * A contrario, all nodes have a long interval of more than 1 (Point right - simply left> 1)

We can therefore immediately whether this or that piece of the tree is a node or a leaf.
But there is also stronger: we can bring only one request:

     * All the elements, and leaf nodes combined, depending on the point of reference (ie under the tree whose root is the element of reference)
     * All independent elements of the reference element (or under trees complementary)
     * All fathers of a reference element

Another way to "see" that tree is to represent him in instalments inclusive. The root is the portion broadest sense, and each sheet is a thin slice:

Constructing the game test to test our queries:
 
CREATE TABLE NEW_FAMILLE
(NFM_BG INTEGER,
NFM_BD INTEGER,
NFM_LIB VARCHAR(16))
INSERT INTO NEW_FAMILLE (NFM_BG, NFM_BD, NFM_LIB)       VALUES (1, 44, 'Transport')
INSERT INTO NEW_FAMILLE (NFM_BG, NFM_BD, NFM_LIB) VALUES (2, 21, 'Air')
INSERT INTO NEW_FAMILLE (NFM_BG, NFM_BD, NFM_LIB) VALUES (3, 4, 'glider')
INSERT INTO NEW_FAMILLE (NFM_BG, NFM_BD, NFM_LIB) VALUES (5, 6, 'Parachute')
INSERT INTO NEW_FAMILLE (NFM_BG, NFM_BD, NFM_LIB) VALUES (7, 8, 'Helico')
INSERT INTO NEW_FAMILLE (NFM_BG, NFM_BD, NFM_LIB) VALUES (9, 10,'Rocket')
INSERT INTO NEW_FAMILLE (NFM_BG, NFM_BD, NFM_LIB) VALUES (11, 12,'ultralight')
INSERT INTO NEW_FAMILLE (NFM_BG, NFM_BD, NFM_LIB) VALUES (13, 20, `Airplane`)
INSERT INTO NEW_FAMILLE (NFM_BG, NFM_BD, NFM_LIB) VALUES (14, 15, 'Military')
INSERT INTO NEW_FAMILLE (NFM_BG, NFM_BD, NFM_LIB) VALUES (16, 17, 'Tourism')
INSERT INTO NEW_FAMILLE (NFM_BG, NFM_BD, NFM_LIB) VALUES (18, 19, 'Civil')
INSERT INTO NEW_FAMILLE (NFM_BG, NFM_BD, NFM_LIB) VALUES (22, 35, 'Terrestrial')
INSERT INTO NEW_FAMILLE (NFM_BG, NFM_BD, NFM_LIB) VALUES (23, 24, 'Bicycle')
INSERT INTO NEW_FAMILLE (NFM_BG, NFM_BD, NFM_LIB) VALUES (25, 26, 'Cars')
INSERT INTO NEW_FAMILLE (NFM_BG, NFM_BD, NFM_LIB) VALUES (27, 28, ' Truck ')
INSERT INTO NEW_FAMILLE (NFM_BG, NFM_BD, NFM_LIB) VALUES (29, 34, 'Moto')
INSERT INTO NEW_FAMILLE (NFM_BG, NFM_BD, NFM_LIB) VALUES (30, 31, 'Side-car')
INSERT INTO NEW_FAMILLE (NFM_BG, NFM_BD, NFM_LIB) VALUES (32, 33, 'Trail')
INSERT INTO NEW_FAMILLE (NFM_BG, NFM_BD, NFM_LIB) VALUES (36, 43, 'Marin')
INSERT INTO NEW_FAMILLE (NFM_BG, NFM_BD, NFM_LIB) VALUES (37, 38, 'Plate Sailing ')
INSERT INTO NEW_FAMILLE (NFM_BG, NFM_BD, NFM_LIB) VALUES (39, 40, ' Liner ')
INSERT INTO NEW_FAMILLE (NFM_BG, NFM_BD, NFM_LIB) VALUES (41, 42, 'Sailboat')

Now how the main complaints expressed by management of this model tree:

2.1. Look all leaves
It is simply to find elements of a length of the interval is one:

SELECT *
FROM NEW_FAMILLE
WHERE NFM_BD - NFM_BG = 1
NFM_BG      NFM_BD      NFM_LIB 
----------- ----------- ----------------
3 4 glider
5 6 Parachute
7 8 Helico
9 10 rocket
11 12 ULM
14 15 Military
16 17 Tourism
18 19 Civil
23 24 Cycling
25 26 Car
...

2.2. All sheets in a reference
In this case it is necessary to restrict the beach edge research to those of the element, always looking for a long intervals.
Example: all leaves under the 'Land' whose edges right and left are: NFM_BG = 22 = 35 and NFM_BD

SELECT *
FROM NEW_FAMILLE
WHERE NFM_BD - NFM_BG = 1
AND NFM_BG > 22
AND NFM_BD < 35
NFM_BG      NFM_BD    NFM_LIB 
----------- ----------- ----------------
23 24 Cycling
25 26 Car
27 28 Truck
30 31 Side-car
32 33 Trail

2.3. Look all nodes
Just find all the elements of a length of the interval of more than one:
SELECT *
FROM NEW_FAMILLE
WHERE NFM_BD - NFM_BG > 1
NFM_BG     NFM_BD     NFM_LIB 
----------- ----------- ----------------
1 44 Transport
2 21 Air
13 20 Aircraft
22 35 Terrestrial
29 34 Moto
36 43 Marin

2.4. All nodes in a reference
In addition to seeking the elements of a length of the interval of more than one, we must also restrict the range of research edges to those of the element.
Example: all the nodes under the 'Transport' NFM_BG which is 1 and 44 is NFM_BD

 

SELECT *
FROM NEW_FAMILLE
WHERE NFM_BD - NFM_BG > 1
AND NFM_BG > 1
AND NFM_BD < 44
NFM_BG      NFM_BD      NFM_LIB 
----------- ----------- ----------------
2 21 Air
13 20 Aircraft
22 35 Terrestrial
29 34 Moto
36 43 Marin

2.5. All elements dependent on a point of reference (subtree)
It is simply find items whose left and right edges are included in the left and right edges of the element.
Example: all elements depending on the 'Ground' which NFM_BG is 22 and NFM_BD is 35

SELECT *
FROM NEW_FAMILLE
WHERE NFM_BG > 22
AND NFM_BD < 35
NFM_BG      NFM_BD      NFM_LIB 
----------- ----------- ----------------
23 24 Cycling
25 26 Car
27 28 Truck
29 34 Moto
30 31 Side-car
32 33 Trail

This request takes the elements hierarchically dependent on the 'Ground', but excluding, while the following query:

SELECT *
FROM NEW_FAMILLE
WHERE NFM_BG >= 22
AND NFM_BD <= 35
NFM_BG      NFM_BD      NFM_LIB 
----------- ----------- ----------------
22 35 Terrestrial
23 24 Cycling
25 26 Car
27 28 Truck
29 34 Moto
30 31 Side-car
32 33 Trail

Retains the same point of reference, which then becomes the root of this sub tree.

2.6. All independent elements of a reference element (in addition to tree)
It is simply retain all the elements whose left side is lower than the left edge of the reference element as well as those whose right side is higher than the right edge of the reference element.
Example: all elements independent element NFM_BG whose land is 22 and NFM_BD is 35

SELECT *
FROM NEW_FAMILLE
WHERE NFM_BG < 22
OR NFM_BD > 35
NFM_BG      NFM_BD      NFM_LIB 
----------- ----------- ----------------
1 44 Transport
2 21 Air
3 4 glider
5 6 Parachute
7 8 Helico
9 10 rocket
11 12 ULM
13 20 Aircraft
14 15 Military
16 17 Tourism
18 19 Civil
36 43 Marin
37 38 Plate Windsurfing
39 40 Paquebot
41 42 Sailboat

It should be noted that in reversing the criteria we obtain research are obtained under the additional trees excluding all fathers of the element:
SELECT *
FROM NEW_FAMILLE
WHERE NFM_BG > 35
OR NFM_BD < 22
NFM_BG      NFM_BD      NFM_LIB 
----------- ----------- ----------------
2 21 Air
3 4 glider
5 6 Parachute
7 8 Helico
9 10 rocket
11 12 ULM
13 20 Aircraft
14 15 Military
16 17 Tourism
18 19 Civil
36 43 Marin
37 38 Plate Windsurfing
39 40 Paquebot
41 42 Sailboat

2.7. All fathers of a reference element
In fact research on all elements including both the left and right edges of the reference element:
Example: all fathers of the 'Moto' whose NFM_BG is 29 and NFM_BD is 34

SELECT *
FROM NEW_FAMILLE
WHERE NFM_BG < 29
AND NFM_BD > 34
NFM_BG      NFM_BD      NFM_LIB
----------- ----------- ----------------
3 46 Transport
24 37 Terrestrial

2.8. Finding the root of the tree
If all insertions are always made by the right, the root has an interval whose left side is a:

SELECT *
FROM   NEW_FAMILLE
WHERE  NFM_BG = 1

Otherwise, one can find the root of the application, meaning that the research on the element of a length of the interval to a unit is nearly double the number of elements:

SELECT *
FROM NEW_FAMILLE
WHERE (NFM_BD - NFM_BG + 1) / 2 = (SELECT COUNT(*)
FROM NEW_FAMILLE)
NFM_BG      NFM_BD      NFM_LIB
----------- ----------- ----------------
1 44 Transport
It may also simply seek the element that has the greatest length intervals: 
SELECT *
FROM NEW_FAMILLE
WHERE (NFM_BD - NFM_BG) = (SELECT MAX(NFM_BD - NFM_BG)
FROM NEW_FAMILLE
Who, of course, leads to the same result. 
2.9. Counting leaves
These are many elements for which the length of the interval is one:
SELECT COUNT(*) AS FEUILLES
FROM NEW_FAMILLE
WHERE NFM_BG = NFM_BD -1
FEUILLES
-----------
16

NOTE: here we have a small variation in the filter WHERE. Rather than spell NFM_BD - NFM_BG = 1, we spent the element NFM_BD the right side of the equal sign, which does not change the value of the equation, but can activate the index of the column NFM_BG, index if there is, what can be assumed it must be a key to this table!

2.10. Counting knots
Counting knots stems from the list of lines with a value of the interval is greater than or different from one:
SELECT COUNT(*) AS NOEUDS
FROM NEW_FAMILLE
WHERE NFM_BG <> NFM_BD -1
NOEUDS
-----------
6
2.11. Insertion of an element in this tree
The particularity of this representation is that tree is a tree lined for which we can choose to insert a left or right of the element father. If it does not matter, choose systematic inclusion on the right which does not need to generate negative values for our terminals and leaves the root with a left edge worth what one can find the root instantly .

Try to insert the item 'Roller' directly connected with his father the 'Land'. In this case, the kiosk right of the 'Land' will serve as a reference because we insert on the right. This right is simply 35.
The insertion orders are as follows:
 
UPDATE NEW_FAMILLE
SET NFM_BD = NFM_BD + 2
WHERE NFM_BD >= 35
UPDATE NEW_FAMILLE
SET NFM_BG = NFM_BG + 2
WHERE NFM_BG >= 35
INSERT INTO NEW_FAMILLE (NFM_BG, NFM_BD, NFM_LIB)
VALUES (35, 36, 'Roller')
In fact shifts on two units all sides, right or left, without distinction of any kind, whose value is greater than or equal to the base right of the father covered by the insertion. 
Another way of looking at things is that the interval father covered by the element to insert into larger of two units to absorb the new son and that this leads all sides to the right of the father a delay of two units.

It is not possible to realise the update in a single complaint. Moreover, if you put a unique constraint on the terminals, it is imperative to begin with the updating of bounds right, then those left and inclusion.
Of course it is better to manage these orders SQL within a transaction.

2.12. Deleting an element of this tree
This can be achieved simply by removing the line corresponding to the element.
Example: abolition of the 'ultralight' (whose NFM_BG is 11):
DELETE FROM NEW_FAMILLE
WHERE NFM_BG = 11
However, this leaves a tree with holes in the management unit intervals. This is not beautiful, but more importantly it can affect some queries that we have seen. The correction of this defect is of great simplicity. It is to renumber a portion of the tree. This is done by considering the value of the left edge of the item to delete and thus shift all sides (left or right) greater than the value of two units to the left (-2). 
In our example, the left edge worth 11, should be run queries following amendment:
UPDATE NEW_FAMILLE
SET NFM_BG = NFM_BG - 2
WHERE NFM_BG >= 11
UPDATE NEW_FAMILLE
SET NFM_BD = NFM_BD - 2
WHERE NFM_BD >= 11
By the same token, it is not possible to achieve the updates into a single order and the removal must act first if there is a risk of téléscopage values bounds. Moreover, if you put a unique constraint on the terminals, it is imperative to begin with the updating of bounds left, then right ones. 

2.13. Deleting a subtree
Removing a tree in full is no more difficult than removing a leaf. It can therefore be achieved by a single complaint or even choose to own and renumber the tree.
For example remove the tree under which the root element 'Terrestrial' Point 22 left and right Point 35:
DELETE FROM NEW_FAMILLE
WHERE NFM_BG >= 22
AND NFM_BD <= 35

Renumerotons then terminals located right under the tree removed, with a gap of 35 - 22 + 1, or 14
UPDATE NEW_FAMILLE
SET NFM_BD = NFM_BD - 14
WHERE NFM_BD >= 22
UPDATE NEW_FAMILLE
SET NFM_BG = NFM_BG - 14
WHERE NFM_BG > 22

Of course the insertion of a subtree (Operation much rarer) is as simple as deleting a subtree.

2.14. The icing on the cake!
Some applications may still appear more difficult, particularly when it comes to search for evidence relating to a level of the tree. For example, the research leaves located at n-1 compared to the level n the reference element. But if such a request may be your daily bread, nothing prevents model the level of element within the table containing the tree. In this case, the table becomes:

CREATE TABLE NEW_FAMILLE
(NFM_BG  INTEGER,
 NFM_BD  INTEGER,
 NFM_NV  INTEGER,
 NFM_LIB VARCHAR(16))

NFM_NV containing the level of element, starting with the zero level, meaning the root of the tree. Therefore changes to be made so requests views reflect the level of elements become trivial.

For example, for research leaves level n + 1 compared to the 'Land', the complaint reads:

SELECT *
FROM   NEW_FAMILLE
WHERE  NFM_BD - NFM_BG = 1
   AND NFM_BG > 22
   AND NFM_BD < 35
   AND NFM_NV = 2

I leave you to guess writing other motions ...
IMPORTANT:
To test the unity of the values of terminals that are in two separate columns, you can use table constraints such as:

CONSTRAINT UNI_BORNE CHECK BORNE_DROITE
(VALUE NOT IN
(SELECT BORNE_DROITE  AS BORNE
 FROM   MaTable
 UNION  ALL
 SELECT BORNE_GAUCHE  AS BORNE
 FROM   MaTable))

et :

CONSTRAINT UNI_BORNE CHECK BORNE_GAUCHE
(VALUE NOT IN
(SELECT BORNE_DROITE  AS BORNE
 FROM   MaTable
 UNION  ALL
 SELECT BORNE_GAUCHE  AS BORNE
 FROM   MaTable))

But few RDBMS accept constraints so complex and it is often necessary to go through triggers to implement such integrity.

STOCKEES PROCEDURES FOR HANDLING OF TREES:

Can be found on the site is an example of the main stored procedures written in Transact SQL (MS) to manage the insertion and removal in such a tree.
Here is an example (for SQL Server) management of a tree with standard nomenclature.

     * Order of creation of the table
     * The two procedures to insert and delete
     * Sight simplifying the presentation of data

-- Creation of the tableT_NOMENCLATURE_NMC
create table T_NOMENCLATURE_NMC
( NMC_ID INTEGER identity,
NMC_LIBELLE CHAR(32) not null,
NMC_DESCRIPTION VARCHAR(1024) null ,
NMC_NIVEAU INTEGER not null,
NMC_BG INTEGER not null,
NMC_BD INTEGER not null,
constraint PK_T_NOMENCLATURE_NMC primary key (NMC_ID))
-- Indexing the table 
CREATE INDEX NDX_NMC_BG ON T_NOMENCLATURE_NMC (NMC_BG)
CREATE INDEX NDX_NMC_BD ON T_NOMENCLATURE_NMC (NMC_BD)
-- Procedure for inclusion in the tree[Frédéric Brouard, Philippe Boucault 25/09/2002]

CREATE PROCEDURE SP_INS_NOMENCLATURE

@lib varchar(32), -- the wording to
@desc varchar(1024), -- description insert
@id_parent int, -- Ancestor brother or point of origin of the insertion mode
@mode char(2) -- the insertion:
-- FA : Son Aine,
-- FC : Son Cadet,
-- GF : Big Brother,
-- PF : Little Brother,
-- P : Father
AS

DECLARE @OK int

DECLARE @bgp int -- simply left parent
DECLARE @bdp int -- terminal right parent
DECLARE @nivp int -- parent level

DECLARE @bgi int -- Simply left to insert
DECLARE @bdi int -- terminal right to insert
DECLARE @nivi int -- level insert

SET NOCOUNT ON

-- management of side-effects mode IS
IF @mode IS NULL OR @lib IS NULL OR @lib = ''
BEGIN
RAISERROR ('Insertion impossible without language or mode!(TABLE T_NOMENCLATURE_NMC)', 16, 1)
RETURN
END

SET @mode = UPPER(@mode)
IF NOT( @mode = 'FA' OR @mode = 'FC' OR @mode = 'GF' OR @mode = 'PF' OR @mode = 'P')
BEGIN
RAISERROR ('Insertion impossible, mode inconnu !', 16, 1)
RETURN
END

-- starting transaction
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
BEGIN TRANSACTION INSERT_NOMENCLATURE


-- no parent => one case, empty table or insertion of a collateral
IF @id_parent IS NULL
BEGIN
SELECT @OK = count(*) FROM T_NOMENCLATURE_NMC
IF @OK = 0 OR @OK IS NULL
BEGIN
IF @mode = 'FA' OR @mode = 'FC'
BEGIN
RAISERROR ('Insertion impossible in a tree for a son without a father!', 16, 1)
GOTO LBL_ERROR
RETURN
END
ELSE
BEGIN
-- the first insertion
INSERT INTO T_NOMENCLATURE_NMC ( NMC_LIBELLE, NMC_DESCRIPTION, NMC_NIVEAU, NMC_BG, NMC_BD )
VALUES( @lib, @desc, 0, 1, 2 )
IF @@ERROR <> 0
BEGIN
GOTO LBL_ERROR
RETURN
END
COMMIT TRANSACTION INSERT_NOMENCLATURE
SELECT @@IDENTITY
RETURN
END
END
ELSE
-- Inserting a collateral
BEGIN
RAISERROR ('Insertion impossible dans un arbre pour un collatéral sans précision du parent !', 16, 1)
GOTO LBL_ERROR
RETURN
END
END

-- The parent still exists?
SELECT @OK = count(*) FROM T_NOMENCLATURE_NMC WHERE NMC_ID = @id_parent
IF @OK = 0 OR @OK IS NULL
BEGIN
RAISERROR ('Insertion impossible, le parent n''existe plus !', 16, 1)
GOTO LBL_ERROR
RETURN
END

--- It was a parent: it recovers its entirety
SELECT @bgp = NMC_BG, @bdp = NMC_BD, @nivp = NMC_NIVEAU
FROM T_NOMENCLATURE_NMC
WHERE NMC_ID = @id_parent

-- insertion of a father
IF @mode = 'P'
BEGIN
-- Shift all right colateral
UPDATE T_NOMENCLATURE_NMC
SET NMC_BD = NMC_BD + 2
WHERE NMC_BD > @bdp
IF @@ERROR <> 0
BEGIN
GOTO LBL_ERROR
RETURN
END
UPDATE T_NOMENCLATURE_NMC
SET NMC_BG = NMC_BG + 2
WHERE NMC_BG > @bdp
IF @@ERROR <> 0
BEGIN
GOTO LBL_ERROR
RETURN
END

-- together referred Decalalage down
UPDATE T_NOMENCLATURE_NMC
SET NMC_BG = NMC_BG + 1,
NMC_BD = NMC_BD + 1,
NMC_NIVEAU = NMC_NIVEAU + 1
WHERE NMC_BG >= @bgp AND NMC_BD <= @bdp
IF @@ERROR <> 0
BEGIN
GOTO LBL_ERROR
RETURN
END

-- Insertion of the new father
INSERT INTO T_NOMENCLATURE_NMC ( NMC_LIBELLE, NMC_DESCRIPTION, NMC_NIVEAU, NMC_BG, NMC_BD )
VALUES( @lib, @desc, @nivp, @bgp, @bdp + 2 )
IF @@ERROR <> 0
BEGIN
GOTO LBL_ERROR
RETURN
END
END

-- Inserting a big brother mode
IF @mode = 'GF'
BEGIN
-- Limit sup.
UPDATE T_NOMENCLATURE_NMC
SET NMC_BD = NMC_BD + 2
WHERE NMC_BD > @bgp
IF @@ERROR <> 0
BEGIN
GOTO LBL_ERROR
RETURN
END

-- Limit inf.
UPDATE T_NOMENCLATURE_NMC
SET NMC_BG = NMC_BG + 2
WHERE NMC_BG >= @bgp
IF @@ERROR <> 0
BEGIN
GOTO LBL_ERROR
RETURN
END

SET @bgi = @bgp
SET @bdi = @bgp + 1
SET @nivi = @nivp
INSERT INTO T_NOMENCLATURE_NMC ( NMC_LIBELLE, NMC_DESCRIPTION, NMC_NIVEAU, NMC_BG, NMC_BD )
VALUES( @lib, @desc, @nivi, @bgi, @bdi )
IF @@ERROR <> 0
BEGIN
GOTO LBL_ERROR
RETURN
END
END


-- Inserting a little brother
IF @mode = 'PF'
BEGIN
-- Limit sup.
UPDATE T_NOMENCLATURE_NMC
SET NMC_BD = NMC_BD + 2
WHERE NMC_BD > @bdp
IF @@ERROR <> 0
BEGIN
GOTO LBL_ERROR
RETURN
END

-- Limit inf.
UPDATE T_NOMENCLATURE_NMC
SET NMC_BG = NMC_BG + 2
WHERE NMC_BG >= @bdp
IF @@ERROR <> 0
BEGIN
GOTO LBL_ERROR
RETURN
END

SET @bgi = @bdp + 1
SET @bdi = @bdp + 2
SET @nivi = @nivp
INSERT INTO T_NOMENCLATURE_NMC ( NMC_LIBELLE, NMC_DESCRIPTION, NMC_NIVEAU, NMC_BG, NMC_BD )
VALUES( @lib, @desc, @nivi, @bgi, @bdi )
IF @@ERROR <> 0
BEGIN
GOTO LBL_ERROR
RETURN
END
END

-- Insertion of an elder son
IF @mode = 'FA'
BEGIN
-- Limit sup.
UPDATE T_NOMENCLATURE_NMC
SET NMC_BD = NMC_BD + 2
WHERE NMC_BD > @bgp
IF @@ERROR <> 0
BEGIN
GOTO LBL_ERROR
RETURN
END

-- Limit inf.
UPDATE T_NOMENCLATURE_NMC
SET NMC_BG = NMC_BG + 2
WHERE NMC_BG > @bgp
IF @@ERROR <> 0
BEGIN
GOTO LBL_ERROR
RETURN
END

SET @bgi = @bgp + 1
SET @bdi = @bgp + 2
SET @nivi = @nivp + 1
INSERT INTO T_NOMENCLATURE_NMC ( NMC_LIBELLE, NMC_DESCRIPTION, NMC_NIVEAU, NMC_BG, NMC_BD )
VALUES( @lib, @desc, @nivi, @bgi, @bdi )
IF @@ERROR <> 0
BEGIN
GOTO LBL_ERROR
RETURN
END
END

-- Inserting a son
IF @mode = 'FC'
BEGIN
-- Limit sup.
UPDATE T_NOMENCLATURE_NMC
SET NMC_BD = NMC_BD + 2
WHERE NMC_BD >= @bdp
IF @@ERROR <> 0
BEGIN
GOTO LBL_ERROR
RETURN
END

-- Limit inf.
UPDATE T_NOMENCLATURE_NMC
SET NMC_BG = NMC_BG + 2
WHERE NMC_BG > @bdp
IF @@ERROR <> 0
BEGIN
GOTO LBL_ERROR
RETURN
END

SET @bgi = @bdp
SET @bdi = @bdp + 1
SET @nivi = @nivp + 1
INSERT INTO T_NOMENCLATURE_NMC ( NMC_LIBELLE, NMC_DESCRIPTION, NMC_NIVEAU, NMC_BG, NMC_BD )
VALUES( @lib, @desc, @nivi, @bgi, @bdi )
IF @@ERROR <> 0
BEGIN
GOTO LBL_ERROR
RETURN
END
END

-- referring to the ID of 'element inserted
SELECT @@IDENTITY

COMMIT TRANSACTION INSERT_NOMENCLATURE
RETURN

LBL_ERROR:
ROLLBACK TRANSACTION INSERT_NOMENCLATURE
-- Procedure of removing the tree[Frédéric Brouard, Philippe Boucault 25/09/2002]

CREATE PROCEDURE SP_DEL_NOMENCLATURE

@id int, -- identifying the target of suppression
@recurs bit -- the method of removal (or non-recursive ):
-- 0 => removes only on that element and it retains the subtree
-- 1 => on that element and removes the subtree
AS

DECLARE @OK int

DECLARE @bgp int -- simply left the target
DECLARE @bdp int -- terminal right of the target
DECLARE @delta int -- variance introduced by the deletion of subtree

SET NOCOUNT ON

-- management of side effects
IF @id IS NULL
BEGIN
RAISERROR ('Removing impossible without identifying set!', 16, 1)
RETURN
END

IF @recurs IS NULL
BEGIN
RAISERROR ('Removing impossible without indication of recursion!', 16, 1)
RETURN
END

-- starting transaction
SET TRANSACTION ISOLATION LEVEL SERIALIZABLE
BEGIN TRANSACTION DELETE_NOMENCLATURE

-- There are always?
SELECT @OK = count(*) FROM T_NOMENCLATURE_NMC WHERE NMC_ID = @id
IF @OK = 0 OR @OK IS NULL
BEGIN
RAISERROR (''Removing impossible, a non-existent!(TABLE T_NOMENCLATURE_NMC)', 16, 1)
GOTO LBL_ERROR
RETURN
END

-- Recovery of terminals target
SELECT @bgp = NMC_BG, @bdp = NMC_BD
FROM T_NOMENCLATURE_NMC
WHERE NMC_ID = @id
IF @@ERROR <> 0
BEGIN
GOTO LBL_ERROR
RETURN
END

-- Removing recursive?
IF @recurs = 1
BEGIN
-- YES! while under the tree should be deleted
-- Calculation of Delta Delta
SET @delta = @bdp - @bgp + 1
-- removal of all elements
DELETE FROM T_NOMENCLATURE_NMC
WHERE NMC_BG >= @bgp
AND NMC_BD <= @bdp
IF @@ERROR <> 0
BEGIN
GOTO LBL_ERROR
RETURN
END
-- shift terminals left
UPDATE T_NOMENCLATURE_NMC
SET NMC_BG = NMC_BG - @delta
WHERE NMC_BG > @bdp
IF @@ERROR <> 0
BEGIN
GOTO LBL_ERROR
RETURN
END
-- shift terminals straight
UPDATE T_NOMENCLATURE_NMC
SET NMC_BD = NMC_BD - @delta
WHERE NMC_BD > @bdp
IF @@ERROR <> 0
BEGIN
GOTO LBL_ERROR
RETURN
END
END
ELSE
BEGIN
-- NOT! removes only one element
-- removing the element
DELETE FROM T_NOMENCLATURE_NMC
WHERE NMC_ID = @id
IF @@ERROR <> 0
BEGIN
GOTO LBL_ERROR
RETURN
END
-- gap terminals and level of the tree under the deleted item
UPDATE T_NOMENCLATURE_NMC
SET NMC_BG = NMC_BG - 1,
NMC_BD = NMC_BD - 1,
NMC_NIVEAU = NMC_NIVEAU - 1
WHERE NMC_BG > @bgp
AND NMC_BD < @bdp
IF @@ERROR <> 0
BEGIN
GOTO LBL_ERROR
RETURN
END
-- gap terminals and level of the tree under the deleted item
UPDATE T_NOMENCLATURE_NMC
SET NMC_BG = NMC_BG - 2
WHERE NMC_BG > @bdp
IF @@ERROR <> 0
BEGIN
GOTO LBL_ERROR
RETURN
END
-- shift terminals left elements located on the right of the deleted item
UPDATE T_NOMENCLATURE_NMC
SET NMC_BD = NMC_BD - 2
WHERE NMC_BD > @bdp
IF @@ERROR <> 0
BEGIN
GOTO LBL_ERROR
RETURN
END
END

COMMIT TRANSACTION DELETE_NOMENCLATURE
RETURN

LBL_ERROR:
ROLLBACK TRANSACTION DELETE_NOMENCLATURE
RETURN
-- Carrying out the request for summary: 
CREATE VIEW V_NOMENCLATURE_NMC
AS
SELECT NMC_ID, CAST(SPACE(NMC_NIVEAU)+ NMC_LIBELLE AS VARCHAR(64)) AS NMC_LIBELLE,
NMC_NIVEAU, NMC_BG, NMC_BD,
(SELECT COUNT(*)
FROM T_NOMENCLATURE_NMC T2
WHERE T2.NMC_BG > T1.NMC_BG
AND T2.NMC_BD < T1.NMC_BD) AS NMC_NBR_DESCENDANT,
NMC_DESCRIPTION
FROM T_NOMENCLATURE_NMC T1
-- Thursday test data: insertion in the tree of the following nomenclature 
METHODES
MERISE
Power Designor
UML
Rational Rose
LANGAGES
Pascal
Delphi
Basic
MS Visual Basic
ASP
PHP
SQL Integres
MS Transact SQL
Oracle PL/SQL
InterBase ISQL
SGBDR
Microsoft
Access
SQL Server
SQL Server 7
SQL Server 2000
MSDE
Borland
InterBase
Oracle
IBM
DB2
SP_INS_NOMENCLATURE 'METHODES', NULL, NULL, 'GF'
NMC_ID      NMC_LIBELLE                      NMC_NIVEAU  NMC_BG      NMC_BD      NMC_NBR_DESCENDANT 
----------- -------------------------------- ----------- ----------- ----------- ------------------
1 METHODES 0 1 2 0
SP_INS_NOMENCLATURE 'MERISE', NULL, 1 , 'FA'
NMC_ID      NMC_LIBELLE                      NMC_NIVEAU  NMC_BG      NMC_BD      NMC_NBR_DESCENDANT 
----------- -------------------------------- ----------- ----------- ----------- ------------------
1 METHODES 0 1 4 1
2 MERISE 1 2 3 0
SP_INS_NOMENCLATURE 'Power Designor', NULL, 2 , 'FA'
NMC_ID      NMC_LIBELLE                      NMC_NIVEAU  NMC_BG      NMC_BD      NMC_NBR_DESCENDANT 
----------- -------------------------------- ----------- ----------- ----------- ------------------
1 METHODES 0 1 6 2
2 MERISE 1 2 5 1
3 Power Designor 2 3 4 0
SP_INS_NOMENCLATURE 'Rational Rose', NULL, 3 , 'PF'
NMC_ID      NMC_LIBELLE                      NMC_NIVEAU  NMC_BG      NMC_BD      NMC_NBR_DESCENDANT 
----------- -------------------------------- ----------- ----------- ----------- ------------------
1 METHODES 0 1 8 3
2 MERISE 1 2 7 2
3 Power Designor 2 3 4 0
4 Rational Rose 2 5 6 0
SP_INS_NOMENCLATURE 'UML', NULL, 4 , 'P'
NMC_ID      NMC_LIBELLE                      NMC_NIVEAU  NMC_BG      NMC_BD      NMC_NBR_DESCENDANT 
----------- -------------------------------- ----------- ----------- ----------- ------------------
1 METHODES 0 1 10 4
2 MERISE 1 2 9 3
3 Power Designor 2 3 4 0
5 UML 2 5 8 1
4 Rational Rose 3 6 7 0
SP_DEL_NOMENCLATURE 5, 1
NMC_ID      NMC_LIBELLE                      NMC_NIVEAU  NMC_BG      NMC_BD      NMC_NBR_DESCENDANT 
----------- -------------------------------- ----------- ----------- ----------- ------------------
1 METHODES 0 1 6 2
2 MERISE 1 2 5 1
3 Power Designor 2 3 4 0
SP_INS_NOMENCLATURE 'UML', NULL, 2 , 'PF'
NMC_ID      NMC_LIBELLE                      NMC_NIVEAU  NMC_BG      NMC_BD      NMC_NBR_DESCENDANT 
----------- -------------------------------- ----------- ----------- ----------- ------------------
1 METHODES 0 1 8 3
2 MERISE 1 2 5 1
3 Power Designor 2 3 4 0
6 UML 1 6 7 0
SP_INS_NOMENCLATURE 'Rational Rose', NULL, 6 , 'FA'
NMC_ID      NMC_LIBELLE                      NMC_NIVEAU  NMC_BG      NMC_BD      NMC_NBR_DESCENDANT 
----------- -------------------------------- ----------- ----------- ----------- ------------------
1 METHODES 0 1 10 4
2 MERISE 1 2 5 1
3 Power Designor 2 3 4 0
6 UML 1 6 9 1
7 Rational Rose 2 7 8 0
etc...
The icing on the cake ...
Here is a view to achieve a stream of XML tree:
 
CREATE VIEW V_TREE_XML_NOMENCLATURE_TXN
AS
SELECT TOP 100 PERCENT WITH TIES BORNE, LIGNE
FROM (SELECT -1 AS BORNE, CAST('<?xml version="1.0" encoding="ISO-8859-1"?>'
AS VARCHAR(1024)) AS LIGNE
FROM V_NOMENCLATURE_NMC
WHERE NMC_ID = (SELECT MIN(NMC_ID) FROM V_NOMENCLATURE_NMC)
UNION
SELECT 0 AS NMC_BG, CAST('<document>' AS VARCHAR(1024)) AS LIGNE
FROM V_NOMENCLATURE_NMC
WHERE NMC_ID = (SELECT MIN(NMC_ID) FROM V_NOMENCLATURE_NMC)
UNION
SELECT NMC_BG AS BORNE, SPACE(NMC_NIVEAU)
+ '<TreeNode><Data LV="'+ CAST(NMC_NIVEAU AS VARCHAR(5))+'"'
+ ' BG="'+CAST(NMC_BG AS VARCHAR(5))+'"'
+ ' BD="'+CAST(NMC_BD AS VARCHAR(5))+'"'
+ ' ID="'+CAST(NMC_ID AS VARCHAR(5))+'"><Name>'
+ RTRIM(LTRIM(NMC_LIBELLE))+'</Name>' AS LIGNE
FROM V_NOMENCLATURE_NMC
UNION
SELECT NMC_BD, CAST(SPACE(NMC_NIVEAU) + '</Data></TreeNode>' AS VARCHAR(1024))
FROM V_NOMENCLATURE_NMC
UNION
SELECT (SELECT MAX(NMC_BD) + 1 FROM V_NOMENCLATURE_NMC) AS NMC_BG,
CAST('</document>' AS VARCHAR(1024)) AS LIGNE
FROM V_NOMENCLATURE_NMC
WHERE NMC_ID = (SELECT MIN(NMC_ID) FROM V_NOMENCLATURE_NMC)) T
ORDER BY BORNE
SELECT LIGNE
FROM V_TREE_XML_NOMENCLATURE_TXN
LIGNE                                                                                                
----------------------------------------------------------------------------------------------------
<?xml version="1.0" encoding="ISO-8859-1"?>
<document>
<TreeNode><Data LV="0" BG="1" BD="10" ID="1"><Name>METHODES</Name>
<TreeNode><Data LV="1" BG="2" BD="5" ID="2"><Name>MERISE</Name>
<TreeNode><Data LV="2" BG="3" BD="4" ID="3"><Name>Power Designor</Name>
</Data></TreeNode>
</Data></TreeNode>
<TreeNode><Data LV="1" BG="6" BD="9" ID="6"><Name>UML</Name>
<TreeNode><Data LV="2" BG="7" BD="8" ID="7"><Name>Rational Rose</Name>
</Data></TreeNode>
</Data></TreeNode>
</Data></TreeNode>
</document>
 
 
< Prev   Next >
School Joomla Templates and Joomla Tutorials