views:

120

answers:

3

Hello guys, sorry if you'll find this question stupid, but I really need help. Here's some info about it.

Database structure


id | parent_id | level | name

1 | 0 | 1 | Home page

2 | 1 | 2 | Child of homepage

3 | 1 | 2 | Another child of homepage

4 | 2 | 3 | Sub child of page id 2

5 | 3 | 3 | Sub child of page id 3


Question


How do I make the SQL statement to group my rows by level and make this output.

Desired output


Home page

~~Child of homepage

~~~~Sub child of page id 2

~~Another child of homepage

~~~~Sub child of page id 3

I know how to do this with a recursion method, but I want to know if I can accomplish this with one SQL statement. Thanks.

A: 

Well, you could order the data by parent_id so that it is sorted correctly:

$menu = mysql_query("SELECT * FROM menu ORDER BY parent_id, level, name");

Then, use the level to determine your indent:

while ($row = mysql_fetch_object($menu)) {
  echo str_repeat('~~', $row->level).' '.$row->name.'<br />';
}

Say you want them in nested lists or some other element (rather than indented by a prefix such as '~~'):

$level = 0;
echo '<ul>';
while ($row = mysql_fetch_object($menu)) {
  if ($row->level > $level) {
    echo '<ul>';
  } else if ($row->level < $level) {
    echo '</ul>';
  }
  echo '<li> '.$row->name.'</li>';
  $level = $row->level;
}
for ($i = $level; $i >= 0; $i--) {
  echo '</ul>';
}
Dustin Fineout
I updated my query with ORDER BY parent_id, level, name , but i still get my data messed and not orderded by levels.
Bdesign
Can you update your answer to show the exact query and data you are getting? I'm not sure why it wouldn't order correctly. The only issue I can think of is if level is somehow a varchar or other text value, then values like '11' would come before '2'. You may also want to check if indexes are defined on those columns, but this shouldn't *prevent* proper ordering from being possible.
Dustin Fineout
Here is the output with the query : SELECT * FROM pages ORDER BY id, level, parent_id ASChttp://aralia.ro/pics/result.png
Bdesign
Yes you need to change it to SELECT * FROM pages ORDER BY parent_id, level, name ASC - you want it to sort by parent_id *first*, level *second*, finally name just so that within a category things are alphabetical.
Dustin Fineout
Now I get this... http://aralia.ro/pics/result%202.png
Bdesign
Oops, I forgot the `$level = $row->level;` line, very important, at the end of the while loop's contents. Updated my answer to contain it, this should fix your issue.
Dustin Fineout
Just wondering if you tried the solution and if it worked out for you.
Dustin Fineout
It's still not showing the results in the right order. Maybe because I have unlimited childs... I managed to get the desired result using a recusive function. Thanks for taking the time to help me.
Bdesign
Hm, seems to me it wouldn't matter if you had unlimited children. I'd be interested to get to the bottom of the problem with my code. Not that I plan to use it myself - I would recommend (and use) a recursive approach anyway, just thought you wanted to avoid it.
Dustin Fineout
Yep, I wanted to avoid it because I heard it's a resource eater when it comes to lots of data. So I thought a simple query will be better. Although, maybe if I would call the childs with a ajax approach when needed, it would be better and more usable. What do you think ?
Bdesign
+1  A: 

I often recommend this article on Storing Hierarchical Data in a Database for questions like this.

The answer to your question is yes, you can get it in just one query. Your method (recursive) is discussed on the first page. Check out page two for the alternative solution, which is the Modified Preorder Tree Traversal (MPTT) design. Using that set-up, you can run a single query and retrieve all the children of a given node of your structure. It's very similar to what you have now, but not quite the same, and will require a bit of work to implement.

For a read-heavy application however, the MPTT is a great algorithm. It requires a bit more work when doing writes, since you have to modify the entire tree structure, but from what you've got set up there I think it might work very well for you.

zombat
I already read that article, and yes, I'm using the method from the first page :Adjacency List Model .My problem is not to list them or other thing. My problem is that I need them in the order I've posted here, because I use JS script to hide children and expand them when needed. If I don't get the right order, the children expand under other parent, so that's not good.
Bdesign
A: 

It can be done using single query which will return the result exactly as you've described. There's a great tutorial on hierarchical data on mysql site.

You can go straight to "Nested Set Model", but I suggest reading the whole tutorial.

Here's the link: http://dev.mysql.com/tech-resources/articles/hierarchical-data.html

Vexatus
The problem is I have unlimited childs, so I can't build up the query like that. And I use the : Adjacency List Model already. The table I've posted it's just a part of it.
Bdesign
You didn't mention that you'll have unlimited children :)
Vexatus
You're right :D
Bdesign