I tried to deal with the same problem 10 years ago. Here is my personal solution to this problem. But before I begin to explain, I would like to mention its pros and cons.
Pros:
You can select the children of a given node in any number of desired depths with the lowest possible cost.
The same can be done for the selection of parent nodes.
No special RDBMS feature required. Thus, the same technique can be implemented in any of them.
Everything is implemented using one field.
Minuses:
You must be able to determine the maximum number of trees. You also need to determine the maximum number of direct children for nodes.
Restructuring a tree is more expensive than moving it. But not as expensive as the Nest Set Model . Adding a new branch is a matter of finding the right value for the field. And to move the branch you need to update the new parent node element and all its children (direct and indirect). The good news is that deleting a node and its children is as simple as traversing it (which is absolutely nothing).
Technics:
Consider the following table as the owner of the tree:
CREATE TABLE IF NOT EXISTS `product_category` ( `product_category_id` bigint(20) unsigned NOT NULL AUTO_INCREMENT, `name` varchar(20) NOT NULL, `category_code` varchar(62) NOT NULL, PRIMARY KEY (`product_category_id`), UNIQUE KEY `uni_category_code` (`category_code`) ) DEFAULT CHARSET=utf8 ;
All magic is performed in the category_code field. You need to encode the address of your branch into a text value as follows:
**node_name -> category_code** Root -> 01 First child -> 01:01 Second child -> 01:02 First grandchild -> 01:01:01 First child of second child -> 01:02:01
In the above example, each node can have up to 99 direct children (provided that we think in decimal form). And since category_code is of type varchar(62) , we can have up to (62-2) / 3 = 20 depth. This is a compromise between the depth you want and the number of direct children each node can have and the size of your field. From a scientific point of view, this is a complete tree implementation in which unused branches are not actually created, but reserved.
Good parts:
Now imagine that you want to select nodes under 01:02 . You can do this using one query:
SELECT * FROM product_category WHERE category_code LIKE '01:02:%'
Selection of direct nodes under 01:02 :
SELECT * FROM product_category WHERE category_code LIKE '01:02:__'
The selection of all ancestors 01:02 :
SELECT * FROM product_category WHERE '01:02' LIKE CONCAT(category_code, ':%')
Bad parts:
Inserting a new node into the tree is a matter of finding the right category_code . This can be done using a stored procedure or even in a programming language such as PHP.
Since the tree is limited by the number of straight children and the depth, the insertion may fail. But I believe that in most practical cases we can assume such a limitation.
Greetings.