0

I have two tables as shown below:

**tblComments**
Commentid
addeddate
Postid


**tblPosts**
Postid
AddedBy
AddedDate
Title

I want to find the total comments for each post. How to do?

Bujo
  • 3
  • 1

5 Answers5

3

You need to join the tables to find posts with no comment to generate zero

select
    count(c.postid), P.postid --edit
from
    tblPosts P 
    LEFT JOIN
    tblComments C On P.postid  = C.postid 
group by
    P.postid 
gbn
  • 422,506
  • 82
  • 585
  • 676
  • 1
    that query will still produce a count of 1 even the tblPosts don't have any comments. change the `COUNT(*)` to `COUNT(c.postid)`. If on Postgres, change the `COUNT(*)` to `COUNT(c.*)`. If you do so, I'll upvote you and remove my answer – Michael Buen Dec 30 '10 at 08:35
  • here's the complete example: http://stackoverflow.com/questions/4561020/t-sql-group-operation/4561081#4561081 – Michael Buen Dec 30 '10 at 09:03
1

To produce zero for post without comments, T-SQL:

select
    P.postid, count(c.postid) -- should not use COUNT(*) for LEFT JOINs
from
    tblPosts P 
    LEFT JOIN
    tblComments C On P.postid  = C.postid 
group by
    P.postid 

For Postgresql, get the cardinality of rows:

select
    P.postid, count(c.*) -- should not use COUNT(*) for LEFT JOINs
from
    tblPosts P 
    LEFT JOIN
    tblComments C On P.postid  = C.postid 
group by
    P.postid 

Related to this: http://www.ienablemuch.com/2010/04/debunking-myth-that-countdracula-is.html

This is why COUNT(*) should not be used on LEFT JOINs:

create table posts
(
post_id int identity(1,1) not null primary key,
post varchar(max)
);

create table comments
(
post_id int not null references posts(post_id),
comment_id int identity(1,1) not null primary key,
comment varchar(max)
);

insert into posts(post) values('hello');

insert into posts(post) values('oh hai');
insert into comments(post_id,comment) values(SCOPE_IDENTITY(), 1);

-- don't
select p.post_id, COUNT(*) as comment_count from
posts p
left join comments c on c.post_id = p.post_id
group by p.post_id

-- do
select p.post_id, COUNT(c.post_id) as comment_count from
posts p
left join comments c on c.post_id = p.post_id
group by p.post_id

Output:

post_id     comment_count
----------- -------------
1           1
2           1


post_id     comment_count
----------- -------------
1           0
2           1

Query-style is more appealing on Postgresql, come to think of it, what we are really counting is the cardinality of the set, not the column(s):

-- looks better on Postgresql, COUNT(c.*)
select p.post_id, COUNT(c.*) as comment_count from
posts p
left join comments c on c.post_id = p.post_id
group by p.post_id
Michael Buen
  • 38,643
  • 9
  • 94
  • 118
  • Can you justify why not COUNT(*) for LEFT JOINs? Sounds like superstition to me http://stackoverflow.com/questions/1221559/count-vs-count1/1221649#1221649 – gbn Dec 30 '10 at 08:27
  • @gbn: it's not superstition, it will still produce a count of 1 even if the `post` doesn't have any corresponding `comments` if you are using left join. you try it. you try to read the article why i also don't believe in using COUNT(1), I encourage the use of `COUNT(*)` or `COUNT(table.*)` (if on Postgresql) – Michael Buen Dec 30 '10 at 08:30
  • the article: http://www.ienablemuch.com/2010/04/debunking-myth-that-countdracula-is.html – Michael Buen Dec 30 '10 at 08:46
  • oops, yes, I was too hasty in interpreting your code comments – gbn Dec 30 '10 at 09:29
0
select count(*), postid from tblPosts group by postid 

should do the trick I would have thought

Yossi Dahan
  • 5,389
  • 2
  • 28
  • 50
0

EDIT: Edited based on your comment below to get all posts including those with 0 comments. Try it out. I think this should work as you expect

SELECT p.Postid, p.Title, ISNULL(X.count,0)
FROM tblPosts p
LEFT OUTER JOIN 
   (SELECT postid, count(commentid) as Total
   FROM tblComments
   GROUP BY Postid) AS X
ON p.Postid = X.Postid
Jagmag
  • 10,283
  • 1
  • 34
  • 58
0
select case(when count(commentid)>0 then count(commentid) else 0 end), postid from tblPosts group by postid 
william
  • 7,284
  • 19
  • 66
  • 106