Unix Technical Forum

Approaching MySQL + Trees

This is a discussion on Approaching MySQL + Trees within the MySQL forums, part of the Database Server Software category; --> Hi, this is my first post to this group, so a 'Hello' to all of you. I think some ...


Go Back   Unix Technical Forum > Database Server Software > MySQL

Register FAQ Members List Calendar Search Today's Posts Mark Forums Read
  #1 (permalink)  
Old 03-17-2008, 06:13 AM
jan.kriesten@silberlicht.de
 
Posts: n/a
Default Approaching MySQL + Trees

Hi,

this is my first post to this group, so a 'Hello' to all of you.

I think some have encountered the need to map a tree to a relational
model and weren't especially happy on what is available. Nested sets
are fast to lookup but messy when it comes to maintaining. Other
approaches use recursive calls with Procedures and - while doing their
job - are limited to a certain recursion level due to database server
setting. Moving the recursion and queries from the dabase to the
client wont push the speed.

I've searched and read a couple of things and came up with the
following solution. I'd happy to get some feedback - especially
regarding the usability and speed where I don't have any hints on
right now.

Best regards, --- Jan.



CREATE TABLE trees (
child_id INT NOT NULL,
parent_id INT NOT NULL,
sib_idx SMALLINT NOT NULL
);

CREATE TABLE nodes (
id INT PRIMARY KEY AUTO_INCREMENT,
title VARCHAR(20)
);


delimiter //

CREATE PROCEDURE addNode( nodeId INT, parentId INT, siblingIdx INT)
BEGIN
DECLARE curChildren INT;
SELECT count(parent_id) into curChildren FROM trees WHERE parent_id
= parentId;
IF siblingIdx <= 0 OR siblingIdx > curChildren THEN
INSERT INTO trees(child_id, parent_id, sib_idx) VALUES(nodeId,
parentId, curChildren+1 );
ELSE
UPDATE trees SET sib_idx = sib_idx+1 WHERE parent_id = parentId
AND sib_idx >= siblingIdx ORDER BY sib_idx DESC;
INSERT INTO trees(child_id, parent_id, sib) VALUES(nodeId,
parentId, siblingIdx );
END IF;
END//


CREATE PROCEDURE getTree( parentId INT )
BEGIN
DECLARE curIdx, curCid, curPid, curLevel, flag INT;

SET curLevel = 1;
SET flag = 0;

DROP TABLE IF EXISTS descendants;
CREATE TEMPORARY TABLE descendants( id INT NOT NULL PRIMARY KEY
AUTO_INCREMENT, depth INT, child_id INT, parent_id INT, sib_idx INT,
INDEX(depth) ) ENGINE=MEMORY;

INSERT INTO descendants values( 0, 0, parentId, -1, -1 );
INSERT INTO descendants SELECT 0, 1, child_id, parent_id, sib_idx
FROM trees WHERE parent_id=parentId AND sib_idx=1;

IF ROW_COUNT() > 0 THEN
this: LOOP
SELECT sib_idx, parent_id, child_id INTO curIdx, curPid, curCid
FROM descendants WHERE depth=curLevel ORDER BY id DESC LIMIT 1;

IF flag = 0 THEN
INSERT INTO descendants SELECT 0, curLevel+1, child_id,
parent_id, sib_idx FROM trees WHERE parent_id=curCid AND sib_idx=1;
END IF;

IF flag = 0 AND ROW_COUNT() > 0 THEN
SET curLevel = curLevel + 1;
ELSE
INSERT INTO descendants SELECT 0, curLevel, child_id,
parent_id, sib_idx FROM trees WHERE parent_id=curPid AND sib_idx=curIdx
+1;
IF ROW_COUNT() = 0 THEN
SET curLevel = curLevel - 1;
SET flag = 1;
ELSE
SET flag = 0;
END IF;
END IF;

IF curLevel = 0 THEN
LEAVE this;
END IF;

END LOOP;
END IF;
SELECT d.depth, CONCAT(REPEAT( ' ', d.depth), n.title ) FROM
descendants d, nodes n where d.child_id=n.id order by d.id;
DROP TABLE descendants;
END//

delimiter ;

--- Example:

INSERT INTO nodes(title) VALUES
('Animals'),
('Mammals'),
('Fish'),
('Carnivores'),
('Herbivores'),
('Tuna'),
('Salmon'),
('Cat'),
('Dog'),
('Horse')
;

call addNode(1,0,0);
call addNode(2,1,0);
call addNode(3,1,0);
call addNode(4,2,0);
call addNode(5,2,0);
call addNode(6,3,0);
call addNode(7,3,0);
call addNode(8,4,0);
call addNode(9,5,0);
call addNode(10,5,0);

call getTree(1);

Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
  #2 (permalink)  
Old 03-17-2008, 06:14 AM
user
 
Posts: n/a
Default Re: Approaching MySQL + Trees

On Wed, 12 Mar 2008 08:16:01 -0700, jan.kriesten wrote:

> Hi,
>
> this is my first post to this group, so a 'Hello' to all of you.
>
> I think some have encountered the need to map a tree to a relational
> model and weren't especially happy on what is available. Nested sets are
> fast to lookup but messy when it comes to maintaining. Other approaches
> use recursive calls with Procedures and - while doing their job - are
> limited to a certain recursion level due to database server setting.
> Moving the recursion and queries from the dabase to the client wont push
> the speed....


I'm fiddling, half-heartedly, with a relational model based on two
separate tables. And I'll be saying a big thanx to the GEDCOM format for
the inspiration.

The first table sets up a genetic breeding pair, taking no note of social
or legal norms,regarding marriage, divorce, or other such frippery - that
comes elsewhere - thusly;

create table family family_id AUTO_INCREMENT, father INT, mother INT;

The other table sets up individuals, and relates them to their parents
breeding pair - again taking no note of social or legal norms regarding
the matter, thusly;

create table individual indiv_id AUTO_INCREMENT, family_id INT, f_name
VARCHAR(), l_name VARCHAR();

This allows me to parse the tree in either direction. Ex. assume I have
an individual, and I want to find his/her ancestors. I put in that
person's ID and search the family he/she came from, then pull mother/
father - again taking note that this is strictly in the genetic sense -
and calling the same look-up, sequentially this time, father, mother. I'm
working with a known geometric progression, so I can set up a memory
table as part of my procedure and populate it from the results of the
query.

Going the other direction, I would take an individual, parse the family
structures for their ID in either the father or mother roles, and search
all individuals for the family ID(s) that turned up in the first search,
then basically reversing the process described in the ancestor search to
give a list of all (known) descendants of that individual.

Maybe consider something like that?
Digg this Post!Add Post to del.icio.usBookmark Post in TechnoratiFurl this Post!
Reply With Quote
Reply


Thread Tools
Display Modes

Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

vB code is On
Smilies are On
[IMG] code is On
HTML code is Off
Trackbacks are On
Pingbacks are On
Refbacks are On
Forum Jump


All times are GMT. The time now is 07:49 PM.


Powered by vBulletin® Version 3.6.5
Copyright ©2000 - 2008, Jelsoft Enterprises Ltd.
Search Engine Optimization by vBSEO 3.2.0
www.UnixAdminTalk.com