SELECT posts, its last 3 comments and count of all comments
My code:
SELECT p.*, u.id, u.username username, u.usersurname usersurname, u.usermainphoto userphoto, GROUP_CONCAT(c.text SEPARATOR 'a!k#h#md%o^v&') commenttext,GROUP_CONCAT(c.likes SEPARATOR '-') commentlikes,GROUP_CONCAT(c.dislikes SEPARATOR '-') commentdislikes, GROUP_CONCAT(c.commentdate) commentdate, GROUP_CONCAT(u2.username) commentauthorname, GROUP_CONCAT(c.anonim) commentanonym, GROUP_CONCAT(c.id) commentid, GROUP_CONCAT(u2.id) commentauthorid, GROUP_CONCAT(u2.usersurname) commentauthorsurname, GROUP_CONCAT(u2.usermainphoto) commentauthorphoto, GROUP_CONCAT(c.commentphotoid) commentphotoid
FROM posts p
LEFT JOIN comments c ON c.post = p.postid AND c.commentdel=0
LEFT JOIN users u ON u.id = p.postauthorid
LEFT JOIN users u2 ON u2.id = c.author
WHERE p.postwallid = :id AND p.postdel=0
GROUP BY postid
ORDER BY postid DESC
it gives me all comments, but I need only 3
You need a timestamp or counter of something to determine which comments are the three you want. Add that column name between the angle brackets below.
SELECT p.*, u.id, u.username username, u.usersurname usersurname, u.usermainphoto userphoto, GROUP_CONCAT(c.text SEPARATOR 'a!k#h#md%o^v&') commenttext,GROUP_CONCAT(c.likes SEPARATOR '-') commentlikes,GROUP_CONCAT(c.dislikes SEPARATOR '-') commentdislikes, GROUP_CONCAT(c.commentdate) commentdate, GROUP_CONCAT(u2.username) commentauthorname, GROUP_CONCAT(c.anonim) commentanonym, GROUP_CONCAT(c.id) commentid, GROUP_CONCAT(u2.id) commentauthorid, GROUP_CONCAT(u2.usersurname) commentauthorsurname, GROUP_CONCAT(u2.usermainphoto) commentauthorphoto, GROUP_CONCAT(c.commentphotoid) commentphotoid
FROM posts p
LEFT JOIN comments c ON c.post = p.postid AND c.commentdel = 0
LEFT JOIN users u ON u.id = p.postauthorid
LEFT JOIN users u2 ON u2.id = c.author
WHERE p.postwallid = :id AND p.postdel = 0
and (
select count(*) from comments as c2
where c2.postid = p.postid and c2.commentdel = 0
and c2.<timestamp> <= c.timestamp
) < 3
GROUP BY postid
ORDER BY postid DESC
Edit: I didn't add the count of all comments. I think you can easily add it with another subquery in the select list but I know MySQL people don't like subqueries very much.
(
select count(*) from comments as c2
where c2.postid = c.postid and c2.commentdel = 0
) as comment_count
I add in SELECT count(postid) as all_comments and at the end LIMIT 0, 3
SELECT count(postid) as all_comments, p.*, u.id, u.username username, u.usersurname usersurname, u.usermainphoto userphoto, GROUP_CONCAT(c.text SEPARATOR 'a!k#h#md%o^v&') commenttext,GROUP_CONCAT(c.likes SEPARATOR '-') commentlikes,GROUP_CONCAT(c.dislikes SEPARATOR '-') commentdislikes, GROUP_CONCAT(c.commentdate) commentdate, GROUP_CONCAT(u2.username) commentauthorname, GROUP_CONCAT(c.anonim) commentanonym, GROUP_CONCAT(c.id) commentid, GROUP_CONCAT(u2.id) commentauthorid, GROUP_CONCAT(u2.usersurname) commentauthorsurname, GROUP_CONCAT(u2.usermainphoto) commentauthorphoto, GROUP_CONCAT(c.commentphotoid) commentphotoid
FROM posts p
LEFT JOIN comments c ON c.post = p.postid AND c.commentdel=0
LEFT JOIN users u ON u.id = p.postauthorid
LEFT JOIN users u2 ON u2.id = c.author
WHERE p.postwallid = :id AND p.postdel=0
GROUP BY postid
ORDER BY postid DESC
LIMIT 0, 3
Related
Here is my SQL query which joins 4 tables and it works correctly.
SELECT pl.lms_id, u.id, REPLACE(trim(u.`url`), 'www.', '') AS url, trim(u.`name`) as name, p.date_removed, p.status, p.ignore_status FROM `adl_seo_status` p INNER JOIN `adl_user_profiles` u on p.profile_id = u.id INNER JOIN adl_tw_profile_acc_type ac on p.profile_id = ac.profile_id LEFT JOIN `adl_lms_prof_list` pl on u.id = pl.profile_id WHERE u.`vpg_id`='2' AND u.`status` = 'Y' and ac.acc_type_id = '2' ORDER BY u.`url` ASC, p.id DESC
I am facing an issue that, the table adl_seo_status has multiple entries for a single profile_id. So, that accounts are repeating in my listing. I want that account as a single row which means the distinct value of accounts based on profile_id.
You need to use group by, for example:
SELECT
pl.lms_id,
u.id,
REPLACE(trim(u.`url`), 'www.', '') AS url,
trim(u.`name`) AS name,
p.date_removed,
p.status,
p.ignore_status
FROM `adl_seo_status` p INNER JOIN `adl_user_profiles` u ON p.profile_id = u.id
INNER JOIN adl_tw_profile_acc_type ac ON p.profile_id = ac.profile_id
LEFT JOIN `adl_lms_prof_list` pl ON u.id = pl.profile_id
WHERE u.`vpg_id` = '2' AND u.`status` = 'Y' AND ac.acc_type_id = '2'
ORDER BY u.`url` ASC, p.id DESC GROUP BY p.profile_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 the following JOIN query already done:
$stmt = $cxn->prepare('SELECT p.post_id, p.reply_to, p.parent_id, p.post_path, p.user_id, p.content, p.datetime, p.total_likes, p.total_replies, p.total_reposts, u.username, u.display_name FROM posts p LEFT JOIN users u ON p.user_id = u.user_id WHERE p.user_id IN (SELECT following_id FROM follows WHERE user_id = ?) AND p.removed != 1 ORDER BY p.datetime DESC LIMIT 26');
$stmt->bind_param('i', $user_info[0]);
$stmt->execute();
I have another query that's only purpose is to check if a row exists or not:
$stmt = $cxn->prepare('SELECT COUNT(like_id) FROM likes WHERE post_id = ? AND user_id = ?');
$stmt->bind_param('ii', $row['post_id'], $user_info[0]); // $row['post_id'] is the value of p.post_id from the first query
$stmt->execute();
How would I join the second query into the first one? I've never joined 3 tables so I'm unsure of the procedure.
Thanks.
Joining three tables in a query is like joining two, except... you join three.
Basically it would go something like this:
SELECT p.post_id (...), u.username (...), COUNT(l.like_id) AS nbOfLikes
FROM posts p
LEFT JOIN users u ON p.user_id = u.user_id
LEFT JOIN likes l ON l.post_id = p.post_id AND l.user_id = u.user_id
WHERE p.user_id IN
(SELECT following_id
FROM follows
WHERE user_id = ?)
AND p.removed != 1
ORDER BY p.datetime DESC
LIMIT 26;
-- Actually I think a UNION would perhaps be more adapted to your need concerning the likes table.
If you always have the user_id filled into your table posts and it's a foreign key, avoid to use a left join statement, you can get a better performance using join statement. To join 3 or more tables you can just add the join statement:
SELECT
p.post_id
, p.reply_to
, p.parent_id
, p.post_path
, p.user_id
, p.content
, p.datetime
, p.total_likes
, p.total_replies
, p.total_reposts
, u.username
, u.display_name
FROM posts p
JOIN users u ON p.user_id = u.user_id WHERE p.user_id IN (SELECT following_id FROM follows
JOIN TABLE_2 ON TABLE_2.id = posts.TABLE_id
JOIN TABLE_3 ON TABLE_3.id = posts.TABLE_id
...
WHERE
user_id = ?)
AND p.removed != 1
ORDER BY p.datetime DESC
LIMIT 26
Okay, so I have a query below I am trying to get to work.
Basically everything works up until the inner join of the 'votes' table. What I am trying to do is order the results of this query in accordance with the number of votes each content row has in another table called votes. I know I'm not too far off from what I need to do!
Thanks in advance!!
mysql_query("
SELECT content.id, content.type, content.title, content.url, users.username
FROM content
INNER JOIN users ON content.uploaderuid = users.id
INNER JOIN votes ON votes.id = content.id
WHERE (content.type = 'pic')
ORDER BY COUNT(votes.id) DESC");
Try doing:
SELECT content.id, content.type, content.title, content.url, users.username
FROM content
INNER JOIN users ON content.uploaderuid = users.id
INNER JOIN (
SELECT id,COUNT(*) as voteCount
FROM votes
GROUP BY id
) v ON v.id = content.id
WHERE (content.type = 'pic')
ORDER BY v.voteCount DESC
When you do an INNER JOIN with votes table directly, if you have multiple occurrences of the same id, you will get a lot more rows than before you did the JOIN.
If you are only interested in the number of votes for each id, by doing a JOIN with a subquery that calculates the count of votes for each id, will leave your previous query results as they were, and lets you use the voteCount to order by it.
You could try this:
SELECT c.id, c.type, c.title, c.url, u.username, COUNT(v.id) votes
FROM content c
INNER JOIN users u ON c.uploaderuid = u.id
INNER JOIN votes v ON v.id = c.id
WHERE c.type = 'pic'
GROUP BY c.id, c.type, c.title, c.url, u.username
ORDER BY votes DESC
Here is the SQL Fiddle that demonstrates the below query:
SELECT c.id, c.type, c.title, c.url, u.username, COUNT(v.id)
FROM content AS c
INNER JOIN users AS u ON c.uploaderuid = u.id
INNER JOIN votes AS v ON v.id = c.id
WHERE c.type = 'pic'
GROUP BY c.id, c.type, c.title, c.url, u.username
ORDER BY COUNT(v.id) DESC
i want to use JOIN categories c ON c.id = i.category if post_type is 1 and i want to have c.title AS category_name, in SELECT otherwise JOIN categories c ON c.id = i.category and c.title AS category_name, must be not worked in query , i'm using case for join but my sql command is not correct. please help me. in all description my quastion means is how to change this below command to if post_type is 1 join must be not work
SELECT SQL_CALC_FOUND_ROWS
i. * ,
c.title AS category_name,
s.title AS status_title,
i.thumb_image,
CONCAT( u.name, ' ', u.family ) AS author
FROM contents i
LEFT JOIN categories c
ON i.category = CASE post_type WHEN 1 then c.id END
JOIN users u ON u.id = i.posted_by
JOIN status_topics s ON s.id = i.t_status
WHERE i.id = 2
I would always do the LEFT JOIN and put a condition on the column itself:
SELECT SQL_CALC_FOUND_ROWS
i. * ,
IF(i.post_type = 1, c.title, NULL) AS category_name,
s.title AS status_title,
i.thumb_image,
CONCAT( u.name, ' ', u.family ) AS author
FROM contents i
LEFT JOIN categories c ON i.category = c.id
JOIN users u ON u.id = i.posted_by
JOIN status_topics s ON s.id = i.t_status
WHERE i.id = 2