SELECT p.id, COUNT(c.id), GROUP_CONCAT(c.id)
FROM mb_post p LEFT OUTER JOIN mb_post c ON c.level LIKE CONCAT(p.level, '.%')
GROUP BY p.id;
+----+-------------+--------------------+
| id | COUNT(c.id) | GROUP_CONCAT(c.id) |
+----+-------------+--------------------+
| 1 | 3 | 4,5,6 |
| 2 | 2 | 7,8 |
| 3 | 2 | 7,8 |
| 4 | 2 | 5,6 |
| 5 | 0 | NULL |
| 6 | 0 | NULL |
| 7 | 1 | 8 |
| 8 | 0 | NULL |
+----+-------------+--------------------+
If you want the count of replies for one specific comment, just use WHERE p.id = ?
before the GROUP BY.
Count only immediate children, not all descendants:
SELECT p.id, COUNT(c.id), GROUP_CONCAT(c.id)
FROM mb_post p LEFT OUTER JOIN mb_post c
ON c.level RLIKE CONCAT('^', p.level, '[.][[:digit:]]+$')
GROUP BY p.id;
+----+-------------+--------------------+
| id | COUNT(c.id) | GROUP_CONCAT(c.id) |
+----+-------------+--------------------+
| 1 | 1 | 4 |
| 2 | 1 | 7 |
| 3 | 1 | 7 |
| 4 | 2 | 5,6 |
| 5 | 0 | NULL |
| 6 | 0 | NULL |
| 7 | 1 | 8 |
| 8 | 0 | NULL |
+----+-------------+--------------------+
Re your comment:
You could use parent_post_id, except as I test it, your parent_post_id's aren't consistent with the hierarchy shown in the level
column. For example, #7 is a child of #2 in level
, but it's the child of #1 in the parent_post_id:
SELECT p.id, COUNT(c.id), GROUP_CONCAT(c.id)
FROM mb_post p LEFT OUTER JOIN mb_post c ON c.parent_post_id = p.id
GROUP BY p.id;
+----+-------------+--------------------+
| id | COUNT(c.id) | GROUP_CONCAT(c.id) |
+----+-------------+--------------------+
| 1 | 2 | 7,4 |
| 2 | 0 | NULL |
| 3 | 0 | NULL |
| 4 | 2 | 5,6 |
| 5 | 0 | NULL |
| 6 | 0 | NULL |
| 7 | 1 | 8 |
| 8 | 0 | NULL |
+----+-------------+--------------------+
This is the risk of storing information redundantly -- it can get out of sync.