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
Related
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.
I have the I site a database that handles 7 different languages, I want to return in one row all the post_content in one row.
Example:
fr_content,en_content,es_content,int_content...
My current sql is returning 7 rows
My sql is:
SELECT p.ID, t.trid, ptrans.*, pen.post_content
FROM hex_posts p
JOIN hex_icl_translations t
ON p.ID = t.element_id
LEFT JOIN hex_icl_translations ptrans
on ptrans.trid = t.trid
LEFT JOIN hex_posts pen
on pen.ID = ptrans.element_id
WHERE
p.ID = 22790
ORDER BY p.post_date DESC
The ID 22790 is the original post, element_id is the post translated.
Any idea how to group all this rows in just one?
Thanks
use group_concat()
SELECT p.ID, t.trid, ptrans.*, group_concat(pen.post_content SEPARATOR ', ')
FROM hex_posts p
JOIN hex_icl_translations t
ON p.ID = t.element_id
LEFT JOIN hex_icl_translations ptrans
on ptrans.trid = t.trid
LEFT JOIN hex_posts pen
on pen.ID = ptrans.element_id
WHERE
p.ID = 22790
group by p.ID, t.trid
ORDER BY p.post_date DESC
So I've got myself in a massive confused mess.
Basically, I have a little social network app and I have 4 different tables I need to combine into one view.
Table 1 - User posts
Table 2 - Users
Table 3 - Likes
Table 4 - Comments
I then need to return a list of posts, with the user details and then add columns for the number of likes and number of comments for each post respectively.
If a post doesn't have any likes or comments, then ideally we should show a Zero.
The query below joins everything up, but returns multiple rows of everything, as it is returning 1 row for each comment or like as well.
Anyone able to help me combine these together?
SELECT *
FROM app_posts AS p
LEFT JOIN app_comments AS c ON c.post_id = p.post_id
LEFT JOIN app_user AS u ON u.user_id = p.user_id
LEFT JOIN app_likes AS l ON l.post_id = p.post_id
WHERE u.user_banned = 0
AND p.post_public = 1
ORDER BY p.post_date DESC
Any help would be greatly appreciated!
Table columns are as follows;
app_likes
like_id
post_id
user_id
liked_date
app_comments
comment_id
comment_user_id
post_id
comment_body
comment_date
app_posts
post_id
user_id
post_content
post_date
post_public
app_user
user_id
user_first
user_last
user_avatar
user_banned
An example of what is returned currently is as follows (chopped down for easiness)
You'll see the post_id is repeated multiple times.
What I want it to return is the post_id just once, and with the count of 'likes' and 'comments' in new columns (I don't know how to do this).
Simon
You might be missing GROUP BY...
SELECT p.*,u.*,count(distinct c.comment_id),count(distinct l.like_id)
FROM app_posts AS p
LEFT JOIN app_comments AS c ON c.post_id = p.post_id
LEFT JOIN app_user AS u ON u.user_id = p.user_id
LEFT JOIN app_likes AS l ON l.post_id = p.post_id
WHERE u.user_banned = 0
AND p.post_public = 1
GROUP BY p.post_id
ORDER BY p.post_date DESC
Note that MySQL lets you be sloppy with GROUP BY like this, but a lot of other databases would require you to break out the "p.*" into explicit MAX(p.post_id),MAX(p.post_content), etc.
SELECT p.post_id, COUNT(c.post_id) as num_comments, COUNT(l.like_id) as num_likes
FROM app_posts AS p
LEFT JOIN app_comments AS c ON c.post_id = p.post_id
LEFT JOIN app_user AS u ON u.user_id = p.user_id
LEFT JOIN app_likes AS l ON l.post_id = p.post_id
WHERE u.user_banned = 0
AND p.post_public = 1
GROUP BY p.post_id
ORDER BY p.post_date DESC
Try to add Group by at the end of your query, like this
SELECT *
FROM app_posts AS p
LEFT JOIN app_comments AS c ON c.post_id = p.post_id
LEFT JOIN app_user AS u ON u.user_id = p.user_id
LEFT JOIN app_likes AS l ON l.post_id = p.post_id
WHERE u.user_banned = 0
AND p.post_public = 1
GROUP BY p.post_id
ORDER BY p.post_date DESC
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
I am using Mysql and have these tables: (only important columns shown)
Person
id, primary key
Post
id, primary key
points, INT
Visit
id, primary key
person_id, refers to Person
post_id, refers to Post
What I want to find is the Persons (top 5) with most points overall? And the persons with most points on each Post.
Can anyone please guide me? Any help is deeply apreciated!
Top 5 persons with most points overall:
SELECT
p.id,
SUM(Post.points) AS total_points
FROM
Person p
INNER JOIN Visit v
ON p.id = v.person_id
INNER JOIN Post
ON v.post_id = Post.id
GROUP BY
p.id
ORDER BY
SUM(Post.points) DESC
LIMIT 5
Top 5 persons with most points in one post:
SELECT
p.id,
MAX(Post.points) AS best_post_points
FROM
Person p
INNER JOIN Visit v
ON p.id = v.person_id
INNER JOIN Post
ON v.post_id = Post.id
GROUP BY
p.id
ORDER BY
MAX(Post.points) DESC
LIMIT 5
Top 5 posts:
SELECT
p.id,
Post.points
FROM
Person p
INNER JOIN Visit v
ON p.id = v.person_id
INNER JOIN Post
ON v.post_id = Post.id
ORDER BY
Post.points DESC
LIMIT 5
For each Post
SELECT id FROM Person where id in (SELECT person_id FROM Visit where post_id in
(SELECT id FROM Post order by points DESC limit 5))
Overall (not sure if will work, not tested)
SELECT id FROM Person where id in (SELECT distinct(person_id) FROM Visit where post_id in
(SELECT id FROM Post order by points DESC limit 5) GROUP BY person_id )
SELECT *
FROM
(
SELECT P.id , SUM(PP.points)
FROM PERSON P JOIN VISIT V ON ( V.person_id = P.id )
JOIN POST PP JOIN ON ( PP.id = V.post_id )
GROUP BY P.id
ORDER BY PP.points DESC
)
LIMIT 5;
SELECT *
FROM
(
SELECT P.id , COUNT(*) NUM_OF_POST
FROM PERSON P JOIN VISIT V ON ( V.person_id = P.id )
JOIN POST PP JOIN ON ( PP.id = V.post_id )
GROUP BY P.id
ORDER BY NUM_OF_POST DESC
)
LIMIT 5;