Reputation: 389
I have a table with the following data:
mysql> describe Post;
+-------------+--------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------+--------------+------+-----+---------+----------------+
| id | int(11) | NO | PRI | NULL | auto_increment |
| user_id | int(11) | NO | MUL | NULL | |
| post_date | datetime | NO | | NULL | |
| in_reply_to | int(11) | YES | | NULL | |
| text | varchar(160) | NO | | NULL | |
+-------------+--------------+------+-----+---------+----------------+
mysql> select id as "Row ID", user_id as "User ID", post_date as "Post Date", IF(in_reply_to is NULL, "None", in_reply_to) as "In Reply To Post ID:", CONCAT(LEFT(text,40),"...") as "Post Text" from Post;
+--------+---------+---------------------+----------------------+---------------------------------------------+
| Row ID | User ID | Post Date | In Reply To Post ID: | Post Text |
+--------+---------+---------------------+----------------------+---------------------------------------------+
| 1 | 1 | 2015-08-14 20:38:00 | None | This is the original test post that I pu... |
| 2 | 2 | 2015-08-14 20:39:00 | None | This is the second post that I put into ... |
| 3 | 5 | 2015-08-14 22:00:00 | 1 | Hahaha, that post was hilarious. I canno... |
| 4 | 4 | 2015-08-14 23:00:00 | 1 | Today I saw a cat jump off the roof, ont... |
| 5 | 4 | 2015-08-14 23:00:00 | None | Today I saw a cat jump off the roof, ont... |
| 27 | 1 | 2015-09-08 05:53:40 | 2 | This is a mad reply ay... |
| 28 | 1 | 2015-09-08 11:24:05 | None | Yolo Swag... |
+--------+---------+---------------------+----------------------+---------------------------------------------+
7 rows in set (0.05 sec)
Each of the columns have a description if you are not sure of what they represent. The two columns I am concerned with for this question are id
and in_reply_to
.
in_reply_to
is a NULLABLE
FK integer that references id
in the same table; if in_reply_to
is NULL
, it means the post is an original post, if it is an integer value, it is a reply post and represents the id of the post that it is a reply to.
In the below example there are 4 original posts (1, 2, 5, 28) and 3 replies (3, 4, 27), ie 3 is a reply to 1, 4 is also a reply to 1, and 27 is a reply to 2. I'm looking to perform an SQL query that produces output like below:
Where Num Replies
is a COUNT
of how rows there are in the same table that have their in_reply_to
equal to id
; displaying 0
if there are no replies to that post (ie no rows contain the id for the particular post as their in_reply_to
column.
Thanks.
Solution (as per Anders' answer):
mysql> SELECT Post.id, Post.user_id, Post.post_date, Post.in_reply_to, CONCAT(LEFT(Post.text,40)), IF(counts.count IS NULL, 0, counts.count) AS 'Num of Replies' FROM Post LEFT JOIN (SELECT in_reply_to AS id, COUNT(*) AS count FROM Post WHERE in_reply_to IS NOT NULL GROUP BY in_reply_to) AS counts ON Post.id = counts.id;
+----+---------+---------------------+-------------+------------------------------------------+----------------+
| id | user_id | post_date | in_reply_to | CONCAT(LEFT(Post.text,40)) | Num of Replies |
+----+---------+---------------------+-------------+------------------------------------------+----------------+
| 1 | 1 | 2015-08-14 20:38:00 | NULL | This is the original test post that I pu | 2 |
| 2 | 2 | 2015-08-14 20:39:00 | NULL | This is the second post that I put into | 1 |
| 3 | 5 | 2015-08-14 22:00:00 | 1 | Hahaha, that post was hilarious. I canno | 0 |
| 4 | 4 | 2015-08-14 23:00:00 | 1 | Today I saw a cat jump off the roof, ont | 0 |
| 5 | 4 | 2015-08-14 23:00:00 | NULL | Today I saw a cat jump off the roof, ont | 0 |
| 27 | 1 | 2015-09-08 05:53:40 | 2 | This is a mad reply ay | 0 |
| 28 | 1 | 2015-09-08 11:24:05 | NULL | Random Text | 0 |
+----+---------+---------------------+-------------+------------------------------------------+----------------+
7 rows in set (0.00 sec)
Upvotes: 1
Views: 246
Reputation: 2588
You can do a join in the traditional way, or you can do the join straight in the new column.
Example:
select a.id,
(select count(*) from (select 1 as id union all select 1 union all select 2)b where b.id=a.id) as count_of_replies
from
(select 1 as id union all select 1 union all select 2)a
note the 2 subquery 'tables' are both the same table.
Upvotes: 0
Reputation: 8577
You need to join two queries on the same table. The first one just selects all the posts, the second one counts the number of replies for each post. It's a left join since you want to include the posts without any replies (that will not be returned from the second query). The IF
is there to convert NULL
values to 0
for those.
SELECT
post.id,
-- Other fields...,
IF(counts.count IS NULL, 0, counts.count) AS count
FROM post
LEFT JOIN
(SELECT
in_reply_to AS id,
COUNT(*) AS count
FROM post
WHERE in_reply_to IS NOT NULL
GROUP BY in_reply_to) AS counts
ON post.id = counts.id
Disclaimar: I have not tested this.
Upvotes: 1