Select distinct to remove duplicate rows? - mysql

I have a forum with a Posts and Comments table. I'd like to sort by recent comments:
select distinct(p.id)
,p.title
,c.id
from Posts as p
,Comments as c
where c.post_id = p.id
order by c.id DESC
LIMIT 50;
However I get a row for every comment. I know I want to loop through the most recent comments and grab the first 50 unique posts. I just can't translate that to SQL.

Here's a solution without subqueries:
SELECT p.id, p.title, MAX(c.id) AS comment_id
FROM Posts AS p
JOIN Comments AS c
ON c.post_id = p.id
GROUP BY p.id
ORDER by comment_id DESC
LIMIT 50
This way may be a bit faster and more scalable despite the subquery because it can optimize on the limit clause:
SELECT p.id, p.title, MAX(c.id) AS comment_id
FROM Posts p
JOIN (SELECT DISTINCT c.post_id FROM Comments c ORDER BY c.id DESC LIMIT 50) t
ON t.post_id = p.id
JOIN Comments c
ON c.post_id = p.id
GROUP BY p.id
ORDER BY comment_id DESC
Make sure there is an index on Comments(post_id).

select p.id
,p.title
,c.id
from Posts as p
,Comments as c
where c.post_id in (
select distict (id)
from posts
)
order by c.id desc
limit 50;
Thanks, Gaurav

You can do so ,by getting the max of comment id for each post group and join with your posts table then do order by comments id
select p.id, p.title, c.id
from
Posts as p
JOIN
(select max(id) id ,post_id
from Comments group by
post_id LIMIT 50) c
ON(c.post_id = p.id)
order by c.id DESC;
Note above query will give the recent comment id only for each post group you can't use * in subquery to fetch the entire row for a comment this means this will not give the recent comment for each post if you select all in subquery
Edit this query will use only one join with limit in inner query so only 50 post's recent comment will be joined and its the inner join so it will take care to returned only associated posts,moreover the performance can be clear if you see the explain plan for your quesries

Related

After 'outer join left ' how to select only 2 data from column associated with the same 'common id' when there's more than 2..?

i have a posts table with columns :
id | content
and a comments table with columns:
id | content | post_id
i used outer left join :
SELECT posts.id, posts.content,comments.content AS comment_content
FROM posts LEFT JOIN
comments
ON comments.post_id = posts.id
ORDER BY posts.id
when i do this i get the Resultset :
as u can see in the below image that i have higlighted from above resultset :
a post has 3 comment associated with it ..(here id and content are of posts)
how do i get only 2 comment associated with a single post id instead of all the comments associated with the post id.(in this case all the comments associated with post_id=5 are 3 comments)
Use row_number():
SELECT p.id, p.content, c.content AS comment_content
FROM posts p LEFT JOIN
(SELECT c.*,
ROW_NUMBER() OVER (PARTITION BY c.post_id ORDER BY c.id DESC) as seqnum
FROM comments c
) c
ON c.post_id = p.id AND c.seqnum <= 2
ORDER BY p.id;
Note: The above returns the two comments with the highest ids -- which are presumably the most recent comments. If you want two random comments, use rand() instead.

How do i sort post in order of highest number of comments

I have 2 tables, posts and comments
Posts
Post_Id
Content
Comments
Comment_id
Content
Post_id
I want to fetch the posts but I want the posts with highest number of comments to appear on top .
Please how do I do this
You can put a correlated subquery in the order by clause:
select p.*
from posts p
order by (select count(*) from comments c where c.post_id = p.post_id) desc
Another option is to pre-aggregate in a subquery. That's also handy if you want to dislay the count of comments:
select p.*, coalesce(c.cnt_comments, 0) cnt_comments
from posts p
left join (select post_id, count(*) cnt_comments from comments group by post_id) c
on c.post_id = p.post_id
order by coalesce(c.cnt_comments, 0) desc

LIMIT row with LEFT join

I have 'post' and 'comment' table. I want select last 3 post and all comments for that posts. Curently I use 2 separate statments:
SELECT p.* FROM post p ORDER BY p.date DESC LIMIT 3; // called 1
SELECT c.* FROM comment c WHERE c.post_id = :id; // called 3x time for each post.
It's possible to marge this queries into one?
You can use a subquery for the set of posts:
SELECT p.*
FROM (SELECT p.*
FROM post p
ORDER BY p.date DESC
LIMIT 3
) p JOIN
comment c
ON c.post_id = p.id
ORDER BY p.id, c.id;
SELECT POST .*, COMMENT.*
from POST INNER JOIN COMMENT ON POST.id = COMMENT.post_id
where POST.id = COMMENT.post_id ORDER BY POST.id LIMIT 3
You can also try this
SELECT p . * , c . *
FROM post p
LEFT JOIN
COMMENT c ON c.post_id = p.id
where p.id IN (SELECT id from post order by date desc limit 3) ORDER BY p.date

Selecting posts that have at least one comment

Basically I want to select all the posts that have at least one comment and get the comment count for each. What I cam up with so far is only giving me one result, which is has an accurate count but there are more than one posts that have comments. Can any recommend changes to make this work
SELECT
posts.id,
COUNT(DISTINCT comments.post_id) AS count
FROM
posts
LEFT JOIN comments ON posts.id = comments.post_id
Using aggregate functions you must group them see here GROUP BY (Aggregate) Functions for the posts must contain atleast one comment you can use HAVING count >= 1
SELECT
posts.id,
COUNT(DISTINCT comments.post_id) AS `count`
FROM
posts
LEFT JOIN comments ON posts.id = comments.post_id
GROUP BY posts.id
HAVING `count` >= 1
You need a group by statement. And you can change the join to an inner join because you want only posts with comments:
SELECT p.id, COUNT(*) AS count
FROM posts p INNER JOIN
comments c
ON p.id = c.post_id
GROUP BY p.id;
The expression count(distinct c.post_id) will return 1 for each row, because there is only one distinct post id for each row. COUNT(*) will get the number of comments.

mysql multiple fields from subquery

SELECT
(SELECT date FROM forums WHERE topic_id=f.id OR id=f.id ORDER BY id DESC LIMIT 1) as last_reply,
f.*, p.id as pid, p.name FROM forums f
INNER JOIN players p ON p.id = f.author
WHERE f.topic_id=0 ORDER BY f.id DESC
In the subquery, I'd like to return not only the date field, but also the author field as well. how can I do this?
looked at a similar post but can't apply it to mine.
I would do it something like this:
SELECT
(SELECT date FROM forums WHERE topic_id=f.id OR id=f.id ORDER BY id DESC LIMIT 1) as last_reply,
(SELECT author FROM forums WHERE topic_id=f.id OR id=f.id ORDER BY id DESC LIMIT 1) as last_author,
f.*, p.id as pid, p.name FROM forums f
INNER JOIN players p ON p.id = f.author
WHERE f.topic_id=0 ORDER BY f.id DESC
I would actually repeat the subquery again
Maybe something like this can help you :
SELECT MAX(f.date), f.author
FROM forums f
INNER JOIN players p ON
p.id = f.author
WHERE f.tpoic_id = 0
GROUP BY f.author
ORDER BY f.id DESC
But it's difficult with no structure of tables.
Good luck.