13

Consider a table like this:

   folders_table
   -----------------------
      INT id_folder
      INT id_folder_parent
      VARCHAR folder_name

Which stores a simple directory structure. How could I get all subdirectories of a directory with a single SELECT query?

6
  • Curious to know why would you want to do this at db level and not at the application layer? Commented Dec 3, 2010 at 13:26
  • 6
    Because one query is much faster than the many queries it would take to build the tree at application level. Commented Dec 3, 2010 at 13:50
  • What is the exact result you're looking for from the query? Do you want the subdirectories of a single, given directory? Do you want a list of every directory paired with all its subdirectories? Do you want to construct the tree structure with the query? Something else? Commented Dec 3, 2010 at 23:47
  • @outis I was looking to just get all subdirectories of a single directory. But I have done it in application logic with recursion for now (I am just quering db server in a recursive function in PHP). It's a little slow but it will have to work for now. Commented Dec 4, 2010 at 1:17
  • I see, now. In other words, you want all descendent directories. "Subdirectories" is ambiguous, as it could be taken to mean all child directories or all descendent directories. Commented Dec 5, 2010 at 1:14

5 Answers 5

17

It is possible, but you need to change your database structure; once the changes are made, you can retrieve a tree of any depth in one query. The queries are slightly more complex, but it's still pretty straightforward.

Sign up to request clarification or add additional context in comments.

5 Comments

The sitepoint link is broken. Do you know where to find another copy of that?
Sorry, I meant the MySQL article. Do you know where to find a copy of that?
No, I don't sorry, but the information was almost exactly the same. At the time that I read them, I found the Sitepoint article to be the clearer of the two, so even if the MySQL one was available I'd recommend using the Sitepoint one.
@Cam: The MySQL article is now on the author's personal site, I added the link.
The name of the described concepts are "Adjacency List Model" and "Nested Set Model" (with "modified preorder tree traversal algorithm"). You can find a lot of information in the net, regarding this topic in <you prefered language>.
3

With the table structure you have shown, this cannot be done with MySQL as it does not support recursive queries

4 Comments

See comment below; it's not possible with this data structure, but it is possible by avoiding recursion and changing the data structure a little.
That's what I said ;) Recursive queries are not possible with MySQL (unlike with other DBMS)
But this can be done with mysql; the OP never said that it had to be done with recursive queries. The approach I point out does it in one query.
I assumed the OP wants to keep the table structure that is already defined. I edited my answer to include this assumption
0

With MySql/MariaDB you can use the Open Query Graph engine (http://openquery.com/graph/doc) which is a mysql plugin that lets you create a special table where you put the relationships, basically parentId and childId.

The magic is that you query this table with a special column latch depending of the value passed in the query will tell the OQGRAPH engine which command to execute. See the docs for details.

It handle not only tree (recursive 1-n relations), but graph data structures (recursive n-m relations) with weight (think for example that you want to store companies ownership, a company can have several subsidiaries and can also have several shareholders).

Comments

0

The other option is to store both the depth of the node and keep an identifier for the complete path of each node and use both of these as criteria.

The way I store XML nodes in a relational database is the following:

SELECT id,value FROM element e1
INNER JOIN element e2 ON (e2.id=e1.parent_id AND name='friend')
WHERE e1.depth>4 AND e1.path like 'root[1]/users[1]/user:dana[1]/public[1]%'

In this example, I've got a field for the node name and an interator in square brackets for duplicate nodes with the same node name at each level in the tree.

When you insert each node, you have to calculate the full path by following the parents down to the root node (parent_id IS NULL) appending each level onto an array, at the same time store the depth of the path.

It is always good in any kind of hierarchy stored in a database to have a visual representation and easy access to any path as following the tree on every request can be costly, especially with mysql which does not have any direct recursive SQL syntax.

The left/right scheme of storing nodes in a hierarchy (nested set adjacency list) is too dangerous in my mind and much more can go wrong with this kind of scheme, for one it is very complicated to manage.

Comments

0

1、create a new table. tree_folder(id, id_folder, tree_id) 2、create a new table. tree(id, tree_json)

The tree table maintain a whole tree node. For example, the following tree with a root node 1.

{
    "folder_id": 1,
    "parent_folder_id": 0,
    "children": [
      {
          "folder_id": 10,
          "parent_folder_id": 1,
          "children": null
      },
      {
          "folder_id": 11,
          "parent_folder_id": 2,
          "children": null
      }
    ]
}

The table contains this row.

[id, tree_json]
[1, "xxxxx"]

Then maintain the relation between the node and tree. As you can see the tree contains the node 1, 10, 11. Then we have the table tree_folder.

[id, folder_id, tree_id]
[1,  1        ,  1]
[2,  10       , 1]
[3,  11       , 1]

When you need get the folder 10's tree. just get from the tree, then deal it in you program.

In this way, you just do recursion in memory instead of mysql.

That is you should maintain the structure when write the data, but the query is easy and fast. If the query is frequent, this works fine. But if the write is frequent, just use a cache instead of this method.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.