views:

681

answers:

5
Hi All, 

I have a table tilted "tbltree"
Structure:
`id` int(10) unsigned NOT NULL auto_increment,
`title` longtext NOT NULL, 
`parent` int(10) unsigned default '0'

Data:

id  Title  parent
1   abc    0
2   xyz    1
3   pqr    1
4   uuu    2

Now I want the results like this

id  title  no of childs
1   abc     3
2   xyz     1
3   pqr     0
4   uuu     0
A: 

If you were using Oracle, I'd suggest using a CONNECT BY which would make this a simple query.

You might be able to do a group by/having as a subselect.

SELECT ID parent_id, TITLE, (
SELECT COUNT(ID) from tbltree group by ID having parent = parent_id) child_count
FROM tbltree;

This is untested, and only works for one level deep on the tree.

Thomas Jones-Low
It looks like this is has been an enhancement request for some time for mysql
Tom
A: 

I haven't had my coffee yet, but you might want to try something along the lines of

select 
    p.id, p.title, count(c.*) 
  from tbltree as c 
  left join tbltree as p 
  where p.id = c.parent 
  group by p.id
  order by p.id
MarkusQ
No coffee yet here either, but that smells right.
Ben S
Marked down, he wanted the descendants not the children.
Tom
@thaggie Then (if you are correct) he should have used the words "all descendants" not "children" and "childs" in the question. SQL I can do. Mind reading, not so much.
MarkusQ
A: 

How about something like this?

SELECT
  a.id,
  a.title,
  COUNT(*) AS children
FROM
  tbltree AS a
  INNER JOIN tbltree AS b ON
    b.parentid=a.id
GROUP BY
  a.id

This requires only one self-join, you would want to have an index on tbltree.id for the GROUP BY statement (presumably you have it as your PRIMARY), and an index on tbltree.parentid to make this join efficient.

thomasrutter
A: 

This should give you what you want EDIT It doesn't....see the last edit below:

select 
  parent.id, parent.title, count(child.id) 'number of children' 
from
  ttt parent left join ttt child
    on child.parent = parent.id
group by parent.id
order by parent.id;

Output from mysql:

+----+-------+--------------------+
| id | title | number of children |
+----+-------+--------------------+
|  1 | abc   |                  2 |
|  2 | xyz   |                  1 |
|  3 | pqr   |                  0 |
|  4 | uuu   |                  0 |
+----+-------+--------------------+

EDIT: At least in MySQL, the ORDER BY is superfluous:

If you use GROUP BY, output rows are sorted according to the GROUP BY columns as if you had an ORDER BY for the same columns. To avoid the overhead of sorting that GROUP BY produces, add ORDER BY NULL

Thanks for the tip, thomasrutter!

EDIT: Well, thaggie pointed out that I'm suffering from a case of not carefully reading the question here. The answer above only gets children of a parent, not all descendants. As others have pointed out, if you're using Oracle you can use their STARTS WTIH/CONNECT BY syntax. Otherwise this article may be of interest.

David Citron
Looks like you, MarcusQ and I got basically the same answer a few minutes apart :) I omitted the ORDER BY because (at least in mysql AFAIK) GROUP BY implies sorting in the same way.
thomasrutter
Heh, yeah. I guess it's a classic self-join kinda question. Thanks for the tip on GROUP BY vs ORDER BY -- the MySQL documentation agrees with you :-)
David Citron
Yeah - you both got the wrong answer, check your results against what he's asking for - you're counting the children he's wanting the descendants.
Tom
@thaggie: Good point. Well, we're back to Oracle "STARTS WITH/CONNECT BY" then, I guess. There's apparently no equivalent in MySQL.
David Citron
A: 

Try reading through this and seeing if it helps.

Tom
there is no any query that count the leaf nodes from treetable