I am working on an sql query where I have three tables posts, users and comments. I want to display all posts with its users and number of comments on this. I have following query but it is giving me wrong result:
SELECT
c.userid, count(c.userid), p.postid
FROM comments c, posts p
where c.userid = p.userid group by c.userid
In addition to above query I also require firstname and lastname from users table.
Try something like this,
SELECT
u.userid, u.firstname, u.lastname,p.post, p.postid,
count(c.userid) totalcoments -- may be c.commentid
FROM users u
JOIN posts p ON p.userid=u.userid
LEFT JOIN comments c OM c.postid=p.postid
GROUP BY u.userid, u.firstname, u.lastname,p.post, p.postid
Try something like the following:
SELECT
postid
, p.userid
, COALESCE((
SELECT COUNT( * ) FROM comments WHERE postid = p.id
), 0 ) AS cnt_postid
, COALESCE( ( SELECT CONCAT( firstname, ' ', lastname ) FROM users WHERE userid = p.userid ), 'N/A' ) AS NAME
FROM posts p
LEFT JOIN comments c ON c.postid = p.id
GROUP BY postid
ORDER BY postid
you are probably getting the same amount of count because you not using a group by.
GROUP BY must always be used when using aggregate function. What the group by does is that it will select all unique posts and the the count will return the number of users for that one unique post
Related
I have two tables: users and courses. Inside users table i have filed course where i have course id. Inside courses table i have just ID and NAME.
I need to get popular course. I do request:
SELECT u.course, COUNT(*) as freq FROM users u INNER JOIN courses c ON u.course = c.id GROUP BY u.course
As a result: id => freq. But i need to replace ID to NAME of course. How?
Thanks.
You don't say what database you use, but I would assume you can use CTEs since most modern databases do. Your query can be written as:
with x as (
select course, count(*) as freq from users group by course
),
y as (
select max(freq) as max_freq from x
)
select c.name, x.freq
from x
join y on x.freq = y.max_freq
join courses c on c.id = x.course
This query has the [desirable?] side effect that it shows more than one course, if there are more than one tied in first place.
Add c.name to both the SELECT clause and the GROUP BY clause.
SELECT u.course, c.name, COUNT(*) as freq
FROM users u
INNER JOIN courses c
ON u.course = c.id
GROUP BY u.course, c.name;
Demo: https://dbfiddle.uk/?rdbms=mariadb_10.3&fiddle=02a41e0f1e6407e516e91c49b4bdc1d2
SELECT u.course, COUNT(*) as freq, c.name FROM users u INNER JOIN courses c ON u.course = c.id GROUP BY u.course
If your DBMS supports row_number this will be suitable:
select t.id, c.name, t.cnt
from course c
join (
select c.id, count(1) cnt, ROW_NUMBER() over(order by count(1) desc) rn
from users u
join course c on c.id = u.course
group by id
)t on t.id = c.id and t.rn = 1
Let's say, I have 3 tables. "users", "topics" and "replies.
The "topics" and "replies" table do have a column "user_id" which references to "id" on the "users" table. The "replies" table also have a column "topic_id" which references "id" on "topics". Also imagine that each topic has 1 reply.
Now, I want to fetch all topics and resolve the username for both tables, so the output should include a "topic_username" and a "reply_username".
I know how to select the username for the topic, but how can I do that for both the topics and replies table?
Thanks
Updated code:
SELECT
t.*,
t_users.username as topic_user,
last_reply.user_id as last_reply_user_id,
r_users.username as last_reply_username,
last_reply.replies_count,
ORDER BY IFNULL(last_reply.created_at,t.created_at DESC
FROM
topics as t
left join users as t_users on t_users.id = t.user_id
left join ( select r.*,count(r.id) as replies_count from (select * from replies order by id desc) as r group by r.topic_id ) as last_reply on last_reply.topic_id = t.id
left join users as r_users on r_users.id = last_reply.user_id
Try this
SELECT
t.*,
t_users.name as topic_user,
r_users.name as reply_user
FROM
topics as t
left join replies as r on r.topic_id=t.id
left join users as t_users on t_users.id = t.user_id
left join users as r_users on r_users.id = r.user_id
this would work well if there is 1:1 topic and reply, if you have 1 to many replies then you are better off group by topic id and get the usernames by group concat
Version 2 (to get reply count and last reply user)
SELECT
t.*,
t_users.name as topic_user,
last_reply.user_id as last_reply_user_id,
r_users.name as last_reply_username,
last_reply.replies_count,
IFNULL(last_reply.created_at,t.created_at) as last_update
FROM
topics as t
left join users as t_users on t_users.id = t.user_id
left join ( select r.*,count(r.id) as replies_count from (select * from replies order by id desc) as r group by r.topic_id ) as last_reply on last_reply.topic_id = t.id
left join users as r_users on r_users.id = last_reply.user_id
ORDER BY IFNULL(last_reply.created_at,t.created_at) DESC
You wanna do this in a single query? You can do it like this but I believe a separate query for fetching replies and topics might be better (fetch replies first, get the unique topic IDs and then fetch topics in a separate query)
SELECT r.id, r.topic_id, ru.username AS reply_username, tu.username AS topic_username
FROM replies AS r
INNER JOIN topics AS t ON (t.id = r.topic_id)
INNER JOIN users AS ru ON (r.user_id = u.id)
INNER JOIN users AS tu ON (t.user_id = u.id)
i create a web app like facebook by php and mysqli
in my app i have a table for posts , one table for likes , and one table for comments
i want to get the number of comments and likes of each post in one row with his post_id!!!
i try some querys likes this :
select `tblpost`.`post_id`, COALESCE(TCOMM.`comment_num`,0) as `c_num`, COALESCE(TLIKE.`like_num`,0) as `l_num`
from
(select `tblpost`.`post_id`, count(*) as `like_num` from `tblpost` join `tbllikes` on `tbllikes`.`post_id` = `tblpost`.`post_id` group by `tblpost`.`post_id`
) TLIKE
inner join
(select `tblpost`.`post_id`, count(*) as `comment_num` from `tblpost` join `tblcomments` on `tblcomments`.`post_id` = `tblpost`.`post_id` group by `tblpost`.`post_id`) TCOMM
on
TCOMM.`post_id` = TLIKE.`post_id`
but i don't know what's my problem
You can do count distincts with two left joins.
Something like this would work if there are fields like_id and comment_id in the tables tbllikes and tblcomments
SELECT
tblpost.post_id AS post_id,
COUNT(DISTINCT tbllikes.like_id) AS likes,
COUNT(DiSTINCT tblcomments.comment_id) AS comments
FROM tblpost
LEFT JOIN tbllikes ON tbllikes.post_id = tblpost.post_id
LEFT JOIN tblcomments on tblcomments.post_id = tblpost.post_id
GROUP BY tblpost.post_id
First, I think you can greatly simplify your query:
select l.post_id,
COALESCE(c.comment_num, 0) as c_num, COALESCE(l.like_num, 0) as l_num
from (select l.post_id, count(*) as like_num
from tbllikes l
group by l.post_id
) l inner join
(select c.post_id, count(*) as comment_num
from tblcomments c
group by c.post_id
) c
on l.post_id = c.post_id;
This will only get you posts that have both likes and comments. To get what you want, use a left join:
select p.post_id,
COALESCE(c.comment_num, 0) as c_num, COALESCE(l.like_num, 0) as l_num
from tblpost p left join
(select l.post_id, count(*) as like_num
from tbllikes l
group by l.post_id
) l
on l.post_id = p.post_id left join
(select c.post_id, count(*) as comment_num
from tblcomments c
group by c.post_id
) c
on c.post_id = p.post_id;
I have two tables :
posts : id,title,content,show,created_at
comments: id,post_id,created_at
I'm trying to order posts by most commented.
SELECT *, COUNT(comments.id) AS total_comments
FROM comments LEFT JOIN posts ON posts.id = comments.post_id
WHERE posts.show = '1'
GROUP BY complains.id
ORDER BY total_comments DESC
The problem is that the posts with 0 comments don't appear.
Any help would be much appreciated.
With your join above, you are incorrectly joining to get commens that have posts
You should have done a right join or swap the tables in left join like below.
Select *, COUNT(comments.id) as total_comments
FROM posts
LEFT outer JOIN comments on posts.id = comments.post_id
WHERE posts.show = '1'
GROUP BY posts.id
ORDER BY total_comments DESC
You need to do a RIGHT JOIN instead of a LEFT JOIN. Or swap the tables in the LEFT JOIN clause.
While there are many ways to solve this, I think this code is easy to read and understand.
The query in the LEFT JOIN can be copied out and run on its own to help debug. Then you join that result set to the posts table and order the results.
SELECT p.*, IFNULL(c.total_comments, 0) as total_comments
FROM posts p
LEFT JOIN (select post_id, count(post_id) as total_comments from comments group by post_id) as c ON p.id = c.post_id
WHERE p.show = '1'
ORDER BY c.total_comments DESC
I have this diagram
What I wanna do is have this output:
How do you manage to do the query of this one?
I have this code
SELECT users.firstname, users.lastname,
users.screenname, posts.post_id, posts.user_id,
posts.post, posts.upload_name,
posts.post_type, posts.date_posted
FROM website.users users
INNER JOIN website.posts posts ON (users.user_id = posts.user_id)
ORDER BY posts.pid DESC
//PROBLEM with this one is that it only views the post from all users.
//SO I added
SELECT COUNT(user_id) AS friends, SUM(user_id = ?) AS you, user_id
FROM feeds WHERE post_id = ?
//This one will give you two fields containing how many different users **feeds** the
post
Please help guys. Actually this one I am just following Facebook's "LIKE" status
the only thing is I'm not an amateur with this kind of stuff so I'd be glad to hear all your answers. I really need your help
If I've understood you correctly, you want an outer join with the feeds table (in order to retain all posts even if there are no associated feeds), then GROUP BY post.pid in order to amalgamate together all such feeds for each post, and SELECT the desired information.
I use MySQL's GROUP_CONCAT() function to obtain a comma-separated list of all users (up to group_concat_max_len) who have
a "feed" for the given post (you can change the delimiter with the SEPARATOR modifier, if so desired).
SELECT users.firstname, users.lastname,
users.screenname, posts.post_id, posts.user_id,
posts.post, posts.upload_name,
posts.post_type, posts.date_posted,
COUNT(feeds.user_id) AS friends, -- number of "likes"
SUM(feeds.user_id = ?) AS you, -- did I like this?
GROUP_CONCAT(feeds.user_id) -- who likes it?
FROM website.users users
INNER JOIN website.posts posts ON (users.user_id = posts.user_id)
LEFT JOIN website.feeds feeds ON (posts.post_id = feeds.post_id)
GROUP BY posts.pid
ORDER BY posts.pid DESC
UPDATE
To obtain the full name of users who have "liked" the post, excluding oneself, one needs to join the users table a second time:
SELECT users.firstname, users.lastname,
users.screenname, posts.post_id, posts.user_id,
posts.post, posts.upload_name,
posts.post_type, posts.date_posted,
COUNT(feeds.user_id) AS friends, -- number of "likes"
SUM(feeds.user_id = ?) AS you, -- did I like this?
GROUP_CONCAT(
CASE WHEN NOT likes.user_id = ? THEN -- exclude self
CONCAT_WS(' ', likes.firstname, likes.lastname) -- full names
END
)
FROM website.users users
INNER JOIN website.posts posts ON (users.user_id = posts.user_id)
LEFT JOIN website.feeds feeds ON (posts.post_id = feeds.post_id)
LEFT JOIN website.users likes ON (feeds.user_id = likes.user_id)
GROUP BY posts.pid
ORDER BY posts.pid DESC
If You want to do it for all the users and simultaneously get the feeds, You have to join this feed table:
SELECT u.firstname, u.lastname,
u.screenname, p.post_id, p.user_id,
p.post, p.upload_name,
p.post_type, p.date_posted,
COUNT(f.user_id) AS friends, SUM(f.user_id = ?) AS you
FROM website.users u
INNER JOIN website.posts p ON (u.user_id = p.user_id)
LEFT JOIN website.feeds f ON (p.post_id = f.post_id)
GROUP BY p.pid
ORDER BY p.pid DESC
This one should do the trick...