What is the most efficient/elegant way to parse a flat table into a tree?

Answer

There are several ways to store tree-structured data in a relational database. What you show in your example uses two methods:

  • Adjacency List (the "parent" column) and
  • Path Enumeration (the dotted-numbers in your name column).

Another solution is called Nested Sets, and it can be stored in the same table too. Read "Trees and Hierarchies in SQL for Smarties" by Joe Celko for a lot more information on these designs.

I usually prefer a design called Closure Table (aka "Adjacency Relation") for storing tree-structured data. It requires another table, but then querying trees is pretty easy.

I cover Closure Table in my presentation Models for Hierarchical Data with SQL and PHP and in my book SQL Antipatterns: Avoiding the Pitfalls of Database Programming.

CREATETABLE ClosureTable (
  ancestor_id   INT NOTNULLREFERENCES FlatTable(id),
  descendant_id INT NOTNULLREFERENCES FlatTable(id),PRIMARYKEY(ancestor_id, descendant_id));

Store all paths in the Closure Table, where there is a direct ancestry from one node to another. Include a row for each node to reference itself. For example, using the data set you showed in your question:

INSERTINTO ClosureTable (ancestor_id, descendant_id)VALUES(1,1),(1,2),(1,4),(1,6),(2,2),(2,4),(3,3),(3,5),(4,4),(5,5),(6,6);

Now you can get a tree starting at node 1 like this:

SELECT f.*FROM FlatTable f 
  JOIN ClosureTable a ON(f.id = a.descendant_id)WHERE a.ancestor_id =1;

The output (in MySQL client) looks like the following:

+----+| id |+----+|1||2||4||6|+----+

In other words, nodes 3 and 5 are excluded, because they're part of a separate hierarchy, not descending from node 1.


Re: comment from e-satis about immediate children (or immediate parent). You can add a "path_length" column to the ClosureTable to make it easier to query specifically for an immediate child or parent (or any other distance).

INSERTINTO ClosureTable (ancestor_id, descendant_id, path_length)VALUES(1,1,0),(1,2,1),(1,4,2),(1,6,1),(2,2,0),(2,4,1),(3,3,0),(3,5,1),(4,4,0),(5,5,0),(6,6,0);

Then you can add a term in your search for querying the immediate children of a given node. These are descendants whose path_length is 1.

SELECT f.*FROM FlatTable f 
  JOIN ClosureTable a ON(f.id = a.descendant_id)WHERE a.ancestor_id =1AND path_length =1;+----+| id |+----+|2||6|+----+

Re comment from @ashraf: "How about sorting the whole tree [by name]?"

Here's an example query to return all nodes that are descendants of node 1, join them to the FlatTable that contains other node attributes such as name, and sort by the name.

SELECT f.name
FROM FlatTable f 
JOIN ClosureTable a ON(f.id = a.descendant_id)WHERE a.ancestor_id =1ORDERBY f.name;

Re comment from @Nate:

SELECT f.name, GROUP_CONCAT(b.ancestor_id orderby b.path_length desc)AS breadcrumbs
FROM FlatTable f 
JOIN ClosureTable a ON(f.id = a.descendant_id)JOIN ClosureTable b ON(b.descendant_id = a.descendant_id)WHERE a.ancestor_id =1GROUPBY a.descendant_id 
ORDERBY f.name

+------------+-------------+| name       | breadcrumbs |+------------+-------------+| Node 1|1|| Node 1.1|1,2|| Node 1.1.1|1,2,4|| Node 1.2|1,6|+------------+-------------+

A user suggested an edit today. SO moderators approved the edit, but I am reversing it.

The edit suggested that the ORDER BY in the last query above should be ORDER BY b.path_length, f.name, presumably to make sure the ordering matches the hierarchy. But this doesn't work, because it would order "Node 1.1.1" after "Node 1.2".

If you want the ordering to match the hierarchy in a sensible way, that is possible, but not simply by ordering by the path length. For example, see my answer to MySQL Closure Table hierarchical database - How to pull information out in the correct order.

All algorithm Questions

Ask your interview questions on algorithm

Write Your comment or Questions if you want the answers on algorithm from algorithm Experts
Name* :
Email Id* :
Mob no* :
Question
Or
Comment* :
 





Disclimer: PCDS.CO.IN not responsible for any content, information, data or any feature of website. If you are using this website then its your own responsibility to understand the content of the website

--------- Tutorials ---