This question is about SQL in general. Answering specifically for MySQL would be helpful but not necessary.
Ok, I’m having trouble putting this into words… so bear with me.
Say I have a tree of things (I’ll call them nodes), with a table that looks something like this (the structure can be changed; this is just a simple version):
+---------+-----------+
| node_id | parent_id |
+---------+-----------+
| 1 | NULL |
| 2 | NULL |
| 3 | 1 |
| 4 | 1 |
| 5 | 5 |
| 7 | 2 |
| 8 | 5 |
+---------+-----------+
Then I have a table of entities. Each entity is associated with a certain node. For example (again, the structure can be changed):
+-----------+---------+
| entity_id | node_id |
+-----------+---------+
| 1 | 1 |
| 2 | 1 |
| 3 | 4 |
| 4 | 7 |
| ...many more rows |
+-----------+---------+
This structure could represent a lot of things, e.g. each entity is a movie, while each node is a genre (but there can be unlimited levels of sub-genres).
So retrieving all the entities for a given node is simple; just running a query on the entities table for a specified node_id
.
Here’s my question: how would I query the entities table for all entities associated with a given node, and all it’s children nodes (every level, recursively). In the movies example, I want to find all movies for a particular genre and all its sub-genres, and its sub-genres, etc.
I mentioned the word recursive, but that doesn’t mean that the query should be recursive, but conceptually it is. The query should be as fast as possible. The structure of the tables may need to be changed as well.
Thanks for your help!
Best Answer
I assume the row (5,5) is a typo, so I used:
as a side note, which representation would you have preferred if you were about to start answering a question, the ascii art in your question, or create and insert statements like above?
To recursively traverse the tree you can use a recursive common table expression (CTE):
I much prefer explicit joins, but the DBMS I'm using does not support them in CTE:
Now it's just a matter of joining this result with your entities table:
This assumes that your DBMS version supports recursive CTE:s. The latest versions of MySQL / MariaDB does.
Another side note, you may want to normalize the tree relation, and keep the structure in a separate relation:
root node(s) are the nodes that are absent in tree
If you are on an older version, or have huge amounts of data and your performance needs to be improved you can add additional information to your model. The most common ones are: