get all comments including its votes for a post - php

I have following three tables in mysql.
postid | post_content => posts
commentid | post | comment_content => comments
commentvoteid | comment | voter => comment_votes
I want to fetch all the comments, counting its votes for a post.
commentid | comment_content | comment_votes => my_result
I have tried the following query but not getting the desired result.
SELECT commentid,comment_content,count_comments.total AS comment_votes
FROM comments
INNER JOIN(SELECT COUNT(*) AS total FROM comment_votes WHERE comment=comments.commentid) AS count_comments
WHERE post={$postId}
Is it possible to fetch the result as I wanted? How can I do that?

You can use GROUP BY to achieve what you want:
SELECT commentid,comment_content,COUNT(*) AS total
FROM comments
INNER JOIN comment_votes ON (comment_votes.comment=comments.commentid)
WHERE post={$postId}
GROUP BY commentid;

The method that you are trying uses a correlated subquery. You can do this, but the correlated subquery needs to go into the select clause:
SELECT c.commentid, c.comment_content,
(SELECT COUNT(*) FROM comment_votes cv WHERE cv.comment = c.commentid
) AS comment_votes
FROM comments c
WHERE post={$postId};
Normally, I much prefer the group by approach but sometimes in MySQL this can be faster.

maybe like this:
select a.commentid, a.comment_content, count(b.*) as total from (
select commentid, comment_content from comments where post={$postId}) a
join comment_votes b on b.comment = a.commentid
group by a.commentid, a.comment_content;

Related

MYSQL : select count with union three table

I have three table content information about posts
and each table has Post_id it's foreign_key for Post table
first table = `likes`
second table = `Comment`
and last one = `Visitor`
each Table has some info about users like session or id and etc
i need to create new view table contain post id and the number of visitor , likes , comment
i tried this
SELECT *
from (
select id , count(id) as Comment
from Post left join Comment on id = Post_id
group by id
UNION
select id, count(id) as Visitor
from Post left join Visitor on id = Post_id
group by id
UNION
select id, count(id) as Likes
from Post left join Likes on id = Post_id
group by id
) CountsTable
GROUP BY CountsTable.id
but it didnt work .
i dont know why the result is only the first inner select
in my example the result is
| id | Comment|
|--------|------- |
| 1 | 55 |
| 2 | 25 |
| 3 | 12 |
i expect something like that
| id | Comment | Likes | Visitor |
|--------------|-------|---------|
| 1 | 55 | 100 | 2000 |
No need to use UNION. Count the records for each post in all three tables and Left Join result with Post table
Try something like this
SELECT id,
comments,
vistors,
likes
FROM Post p
LEFT JOIN (SELECT Count(Post_id) comments, Post_id
FROM Comment
GROUP BY Post_id) c
ON p.id = c.Post_id
LEFT JOIN (SELECT Count(Post_id) vistors, Post_id
FROM Visitor
GROUP BY Post_id) v
ON p.id = v.Post_id
LEFT JOIN (SELECT Count(Post_id) likes, Post_id
FROM Likes
GROUP BY Post_id) l
ON p.id = l.Post_id
You can do it with a Left Join query, e.g.:
select u.id, count(distinct l.id) as likes, count(distinct c.id) as comments
from user u left join likes l on u.id = l.user_id
left join comments c on u.id = c.user_id
group by u.id;
Here is SQL Fiddle.
SELECT id, SUM(Comment),SUM(Visitor),SUM(Likes) from (
select id , count(id) as Comment, 0 as Visitor, 0 as Likes
from Post left join Comment on id = Post_id
group by id
UNION ALL
select id, 0 as Comment, count(id) as Visitor , 0 as Likes
from Post left join Visitor on id = Post_id
group by id
UNION ALL
select id, 0 as Comment, 0 as Visitor, count(id) as Likes
from Post left join Likes on id = Post_id
group by id
) CountsTable
GROUP BY CountsTable.id

MySQL Query join last comment to topic

I have a topic and topic_comments table. I want to join them both.
+------------+ +------------+
| Topic | | Comments |
+------------+ +------------+
| id | | parent_id |
| title | | content |
| createdate | | createdate |
| content | | creator_id |
+------------+ +------------+
The join is on topic.id = topic_comments.parent_id. I want to show the topic with latest comment and order by latest comment createdate. And not show duplicate topics. Can anyone help me?
So far I have this:
select p.id, p.title, p.createdate, p.content, p.int_0 as reacties_total, p.char_1 as prio, p.char_0 as status, r.createdate as r_createdate, r.creator_id as r_creator_id, r.content as r_content
from pages p, topic_reacties r
where r.parent_id = p.id
and p.parent_id = ' . $this->id . '
order by p.int_2 desc
This however doesn 't show topics without comments. It only returns topics with reactions.
Do you want to show topics with the latest comment and sorted by comment or every topic whether it has a comment or not? Those are two different requirements.
If you want to show topics with the latest comment, use the join just as you did (except please lose the archaic syntax), but add more detail to the on clause:
select p.id, p.title, p.createdate, p.content,
p.int_0 as reacties_total, p.char_1 as prio,
p.char_0 as status, r.createdate as r_createdate,
r.creator_id as r_creator_id, r.content as r_content
from pages p
join topic_reacties r
on r.parent_id = p.id
and r.createdate =(
select Max( createdate )
from topic_reacties
where parent_id = r.parent_id )
order by r.createdate;
Don't let the subquery scare you. Test it and you will see impressive efficiency -- if the createdate column is indexed.
If you want all topics whether they have a comment or not but those with comments only the latest one, then use an outer join. You would still use the same subquery but some DBMSs don't allow subqueries in the on clause of outer joins. Oracle for instance. I'm not sure about MySQL. In any event, I always move it to the where clause just to be safe. (I deal with a lot of different DBMSs.)
However, when you place a check of the outer table of an outer join in the where clause, you can convert the output to be the same as an inner join. So you have to use a little trick.
select p.id, p.title, p.createdate, p.content,
p.int_0 as reacties_total, p.char_1 as prio,
p.char_0 as status, r.createdate as r_createdate,
r.creator_id as r_creator_id, r.content as r_content
from pages p
left join topic_reacties r
on r.parent_id = p.id
where (r.parent_id is null
or r.createdate =(
select Max( createdate )
from topic_reacties
where parent_id = r.parent_id ))
order by r.createdate;
Note that I've placed parentheses/brackets around the where check although, as written, they are not absolutely necessary. However, if you add any other check you will need them to go outside the parentheses.
where (r.parent_id is null
or r.createdate =(
select Max( createdate )
from topic_reacties
where parent_id = r.parent_id ))
and p.ID = :SomeID
Check out the SQL Fiddle
SELECT title,content,max(createdate) as createdate
FROM topic
left join comments
on topic.id=comments.parent_id
group by title
order by createdate desc;

Slow query using "where in" and "order by select count"

I want to show post from users that specified user is followed and i have two tables at below. but its query is very slow.
table user
id | username
1 | name1
2 | name2
3 | name3
..
..
table post
id | poster_id | post_content
1 | 2
2 | 3
3 | 10
..
..
table follow
followerid | followtoid
1 | 2
1 | 3
2 | 10
..
..
Assume that all tables have more than 1000 rows.
This's SQL
SELECT *
FROM post
WHERE poster_id IN (
SELECT followtoid
WHERE followerid = $_SESSION['userid']
)
And this's the second cast is very slow too.
I want to list all member by order from their total posts.
SELECT *
FROM user
ORDER BY (
SELECT COUNT(id)
FROM post
WHERE post_id = user.id
) DESC;
Try indexing post.userid, post.poster_id, followtoid.followerid and user.user_id, using CREATE INDEX, and use LEFT JOIN clause on your queries instead:
SELECT *
FROM user u
LEFT JOIN SELECT poster_id, COUNT(*) as count FROM post p GROUP BY poster_id
ON (u.user_id = p.poster_id)
ORDER BY count DESC;
and:
SELECT * FROM post AS p
LEFT JOIN (SELECT followerid FROM followtoid) AS f
ON (p.userid=f.followerid)
WHERE p.userid = {$_SESSION['userid']}
Use a JOIN for the first query
SELECT p.*
FROM post p
JOIN follow f ON p.post_id = f.followtoid
WHERE f.followerid = $_SESSION['userid']
and a JOIN plus a GROUP BY for the second
SELECT u.*, tbl.postCount
FROM user u
JOIN (
SELECT poster_id, COUNT(*) AS postCount
FROM post p
GROUP BY posterID
) tbl ON tbl.poster_id = u.id
ORDER BY postCount DESC
You can accomplish the second query without a subquery:
SELECT u.*, COUNT(p.poster_id) as postCount
FROM user u
LEFT JOIN post p
ON (u.user_id = p.poster_id)
GROUP BY u.user_id
ORDER BY postCount DESC;

Inner Join Query Advice

i need help on creating an inner join query.
I have 2 tables, blogs and followers.
In the blogs table i have all the blog information, and then in the followers i have two fields which are the user id and then the blog id that the user follows.
I want to create a query that will order the blogs by how many followers there are.
So this is an example of what i use to show what builds a user is following (for reference):
$query = "SELECT * FROM blogs INNER JOIN followers ON (blogs.id = followers.blogid) WHERE followers.userid='" .$usernamesesh. "'";
How can i go about creating a similiar query that will select all the blogs, but order them by highest to lowest followers.
Hope this makes sense, i cant get my head around this one for some reason!
The only other option is to add a number of followers field in the blogs table but that would involve changing my follow script etc.
Craig.
Without knowing the exact structure of you tables it's hard to tell. Assuming your followers table looks something like this
blogid | userid
-------+----------
1 | 2
-------+----------
1 | 1
-------+----------
1 | 3
-------+----------
2 | 2
-------+---------
SELECT blogid, COUNT(userid) AS UserCount FROM followers
GROUP BY blogid ORDER BY UserCount DESC;
You can then to join the blogs table to get what ever columns you need from that table.
SELECT blogs.*, IFNULL(f.UserCount,0) AS UserCount
FROM blogs
LEFT JOIN (
SELECT blogid, COUNT(userid) AS UserCount FROM followers
GROUP BY blogid
) f
ON f.blogid = blogs.id
ORDER BY UserCount DESC
I would recommend tweaking Mihai's suggestion a little bit, so add this string to the end of your query: GROUP BY blogs.id ORDER BY COUNT(userid) DESC
$query = "SELECT blogs.id, count(*) AS total FROM blogs INNER JOIN followers ON (blogs.id = followers.blogid) WHERE followers.userid='" .$usernamesesh. "'" GROUP BY blogs.id ORDER BY total;
Hope this helps
You could join against a subquery:
SELECT blogs.*, s.cnt
FROM blogs
LEFT JOIN (SELECT blogid, count(*) as cnt
FROM followers
GROUP BY blogid) s
ON s.blogid = blogs.id
ORDER BY s.cnt
Edit
With
CREATE TABLE blogs (id);
create TABLE followers(blogid);
INSERT into blogs values (1),(2),(3);
INSERT into followers values (1),(1),(3);
You get:
id cnt
---------- ----------
2
3 1
1 2

Display only the newest record for each row in MySQL db using PHP

I have two tables of which one is updated daily. I would like to display "only" the latest record for each row.
This is the query I am using now that of course returns all the records.
SELECT *
FROM ss_pumps, secondary_systems WHERE ss_pumps.id=secondary_systems.segment_id
ORDER BY id ASC
Any help would be greatly appreciated!
You can find the latest record for every segment_id by ID using subquery. The result of the subquery is then join against the two tables: ss_pumps and secondary_systems.
SELECT a.*, c.*
FROM ss_pumps a
INNER JOIN
(
SELECT segment_id, MAX(datefield) max_val
FROM secondary_systems
GROUP BY segment_id
)b ON a.id = b.segment_id
INNER JOIN secondary_systems c
ON b.segment_id = c.segment_id AND
b.max_val = c.datefield
Actually, I'm not sure how your tables: ss_pumps and secondary_systems are related with each other.
I think you want it the other ways,
SELECT a.*, b.*
FROM secondary_systems a
INNER JOIN ss_pumps b
ON a.segment_ID = b.segment
INNER JOIN
(
SELECT segment, MAX(ID) max_val
FROM ss_pumps
GROUP BY segment
) c ON b.segment = c.segment AND
b.ID = c.max_val
Use this query:
SELECT * FROM ss_pumps, secondary_systems WHERE ss_pumps.id=secondary_systems.segment_id ORDER BY id DESC LIMIT 1
This is assuming that id is an auto increment column and will always be inserted in order.
Here's what I got:
SELECT *
FROM
ss_pumps ssp
LEFT JOIN ( SELECT * FROM secondary_systems ORDER BY id DESC ) ss ON ( ssp.id = ss.segment_id )
GROUP BY
ssp.id
ORDER BY
ssp.id ASC
CAVEAT: I'm assuming that the secondary_systems has its own id field that also autoincrements. That's the only way you can make sure you're getting "only" the latest record for each row.
Demo: http://sqlfiddle.com/#!2/f816b/2/0
In my demo ss_pumps held the parents while secondary_systems held the children. Each parent has 3 children. All but the last children are boys. The last child is always a girl. According to your problem, the resulting query should yield only girls.
| ID | PARENT | SEGMENT_ID | CHILD |
------------------------------------
| 1 | mother | 1 | betty |
| 2 | father | 2 | tina |

Categories