join 3 sql tables and make nested query - mysql

So I have 3 tables called comments, users and posts.
I want to get
the "score" from comments
the "user reputation" for users by doing the left join between comments and users with c.user_id = u.id
get the "tags" from posts table by doing a left join between comments and posts on c.post_id = p.id.
BUT there is a trick here the tags should be based on the type of the posts (p.post_type_id).
So if the id = 1 then that means we have a "question" as a post and simply retrieve tag
Else if the id = 2 then that means we have an answer and to get the tag we have to look at its parent_id from posts table.
I tried to use WHERE, CASE, nested IF, and nested SELECT but all threw syntax errors
Finally, I tried to do the following but I got an empty result
SELECT c.score,
COALESCE (u.reputation) reputation,
COALESCE (p.tags) tags
FROM comments c
LEFT JOIN users u
ON c.user_id = u.id
LEFT JOIN posts p
ON (c.post_id = p.id AND p.post_type_id = 1) OR (c.post_id = p.id AND p.post_type_id = 2 )
WHERE (p.id = p.parent_id)
So how can I have the tags based on the two types ?

Just quick guess:
http://sqlfiddle.com/#!9/a1cc3/1
SELECT c.score,
u.reputation reputation,
IF(p.post_type_id=1,p.tags,
IF(p.post_type_id=2,parents.tags,'UNKNOWN POST TYPE')
) tags
FROM comments c
LEFT JOIN users u
ON c.user_id = u.id
LEFT JOIN posts p
ON c.post_id = p.id
LEFT JOIN posts parents
ON parents.id = p.parent_id
UPDATE Here is Postgres variant:
http://sqlfiddle.com/#!15/a1cc3/2
SELECT c.score,
u.reputation,
CASE p.post_type_id
WHEN 1 THEN p.tags
WHEN 2 THEN parents.tags
ELSE 'UNKNOWN POST TYPE'
END tags
FROM comments c
LEFT JOIN users u
ON c.user_id = u.id
LEFT JOIN posts p
ON c.post_id = p.id
LEFT JOIN posts parents
ON parents.id = p.parent_id

Related

query in mysql with node js

i am trying to get comments likes and dislike in post but i cant get comments in strings
SELECT p.*, u.full_name as post_author,c.*,l.*, GROUP_CONCAT(c.comment SEPARATOR ',') as comments, GROUP_CONCAT(u3.id SEPARATOR '#') as post_likers FROM post p LEFT JOIN posts_comments c ON c.post_id = p.id LEFT JOIN post_like_dislike l ON l.post_id = p.id LEFT JOIN user u ON u.id = p.user_id LEFT JOIN user u2 ON u2.id = c.user_id LEFT JOIN user u3 ON u3.id = l.user_id GROUP BY p.id
i have tried this query but getting the proper result
.enter image description here
i am getting comments like this but i want comments with user name and comment ..
there are 3 different tables comments post and like
i want to get all comment of a post in post and in string or json formenter image description here
like this .. i am using node JS with mysql
If you want a SQL-only solution, try this
SELECT p.*, u.full_name as post_author,c.*,l.*,
IF(c.id IS NOT NULL, JSON_ARRAYAGG(JSON_OBJECT('id', c.id, 'comment', c.comment)), NULL) AS comments,
IF(u3.id IS NOT NULL, JSON_ARRAYAGG(JSON_OBJECT('id', u3.id)), NULL) AS post_likers
FROM post p
LEFT JOIN posts_comments c ON c.post_id = p.id
LEFT JOIN post_like_dislike l ON l.post_id = p.id
LEFT JOIN user u ON u.id = p.user_id
LEFT JOIN user u2 ON u2.id = c.user_id
LEFT JOIN user u3 ON u3.id = l.user_id
GROUP BY p.id
Note: there are many ORM out there already handle query relationship like this, give it a try.

MySql: Check where clause for all row returned by an inner join

I have this query
SELECT *
FROM posts
INNER JOIN categories ON categories.post_id = posts.id
INNER JOIN tags ON tags.category_id = categories.id
WHERE tags.title = 'week_trend'
Each posts has multiple categories and also each category has multiple tags and I need the posts that have the categories with the specified tag but all the post categories should have this condition and even if one of those categories failed the condition the post shouldn't be included. My query returns the posts even if one of their categories has the specified tag.
I almost have no idea how to do it can someone help me tnx
This query:
SELECT c.post_id
FROM categories c INNER JOIN tags t
ON t.category_id = c.id
GROUP BY c.post_id
HAVING COUNT(DISTINCT c.id) = SUM(t.title = 'week_trend')
returns all the post_ids with categories that are all related to the tag with title 'week_trend'.
Use it with an IN clause:
SELECT *
FROM posts
WHERE id IN (
SELECT c.post_id
FROM categories c INNER JOIN tags t
ON t.category_id = c.id
GROUP BY c.post_id
HAVING COUNT(DISTINCT c.id) = SUM(t.title = 'week_trend')
)

Get results when where value is 'grade' or where it doesn't exist

I have a wordpress site that is used to store student grades on various lessons (from the quizzes on the site). I am trying to create a query that will pull out all of the lessons for all students in a certain group (using buddypress groups) and the students grades in each lesson.
I have created this query:
SELECT u.display_name, p.post_title, cm.meta_value
FROM wp_users u
JOIN wp_bp_groups_members gm
ON u.ID = gm.user_id
JOIN wp_comments c
ON u.ID = c.user_id
JOIN wp_commentmeta cm
ON c.comment_ID = cm.comment_id
JOIN (SELECT * FROM wp_posts WHERE post_type LIKE 'lesson') p
ON c.comment_post_id = p.ID
WHERE gm.group_id = 4 AND cm.meta_key LIKE 'grade'
This currently returns all the grades for all students in a group in the lessons they have attempted the test. However it does not return any lessons they have not attempted the test in, which I need still.
Just to be clear: lessons are posts, grades are meta_values in a record with a meta_key of 'grades'. These are stored as comments, and comment_meta.
I hope this is all clear and you can help. Thanks.
After Ollie Jones help I made this:
SELECT u.display_name, p.post_title, IFNULL(cm.meta_value,'--nothing--') grade
FROM wp_users u
JOIN wp_comments c
LEFT JOIN wp_commentmeta cm
ON c.comment_ID = cm.comment_id AND cm.meta_key = 'grade'
JOIN wp_bp_groups_members gm
ON u.ID = gm.user_id
JOIN wp_posts p
ON c.comment_post_id = p.ID
WHERE gm.group_id = 4 AND p.post_type LIKE 'lesson'
Which almost works but returns all student grades, not just the ones in the group (though it only gives the one name of the student in the group).
This is the familiar key/value store problem, that comes up with commentmeta, postsmeta, and usermeta. When you JOIN two tables and the left one might not have a corresponding row, you need to use LEFT JOIN. When the left one is a key/value table, you need to adjust the ON condition accordingly. Finally, when you LEFT JOIN two tables and there's no matching row in it it, you get back NULLs for those columns, so you must allow for that.
So this kind of SQL pattern will do the trick for you
SELECT whatever, IFNULL(cm.meta_value,'--nothing--') grade
FROM whatever
LEFT JOIN wp_comments c ON whatever.id = c.user_id
LEFT JOIN wp_commentmeta cm ON c.comment_id = cm.comment_id
AND cm.meta_key = 'grade'
JOIN whatever
Is there a user_id in your comments table? I dont see where you joined which user posted which comment. So when you join the group_members to the users table, you are specifying which users to show, but since you are not joining on user id when you join to your comments table, it will show all the comments for all the users. Im not sure if this will work for your table, but try:
SELECT u.display_name, p.post_title, IFNULL(cm.meta_value,'--nothing--') grade
FROM wp_users u
LEFT JOIN wp_comments c
JOIN wp_commentmeta cm
ON c.comment_ID = cm.comment_id AND cm.meta_key = 'grade'
JOIN wp_bp_groups_members gm
ON c.user_ID = gm.user_id
ON u.user_id = c.user_id
JOIN wp_posts p
ON c.comment_post_id = p.ID
WHERE gm.group_id = 4 AND p.post_type LIKE 'lesson'
Hope this helps!

Mysql query help. I need to make sure atleast one record is returning

I have a query that I know it should atleast return one row. How can i modify my follow query to make sure that album returns data. thanks for any help.
Query Here. I know that Album has a row and I need to return it.
select distinct p.*,
a.ID as parentalbumid,a.CreatorID as albumcreatorid,a.AlbumName,a.AlbumDescription,a.AlbumDefaultImageURL,a.Private,a.DateCreated,a.AdultContent,a.PasswordProtected,a.AllowTags,a.TypeID,a.AlbumAutoID,
mainuser.Username as mainuserusername,mainuser.ID as mainuserid,mainuser.PictureUrl as mainuserpictureurl,
c.ID as commentID,c.PhotoID as commentphotoid,c.OutputMessage,c.CommentDate,
t.ID as tagID,t.PhotoID as tagphotoid,t.UserID,t.TextTag,t.LeftLocation,t.TopLocation,
u.ID as userid,u.Username,u.FirstName,u.LastName,u.PictureUrl
from photos p
inner join albums a on a.ID = p.AlbumID
inner join users mainuser on mainuser.ID = p.UserID
left join comments c on c.PhotoID = p.ID
left join tags t on t.PhotoID = p.ID
left join users u on u.ID = c.CommentBy
where a.AlbumAutoID = 3
order by p.DateUploaded desc;
Use only LEFT JOINs (and put the table albums as the first table of your FROM):
select distinct p.*,
a.ID as parentalbumid,a.CreatorID as albumcreatorid,a.AlbumName,a.AlbumDescription,a.AlbumDefaultImageURL,a.Private,a.DateCreated,a.AdultContent,a.PasswordProtected,a.AllowTags,a.TypeID,a.AlbumAutoID,
mainuser.Username as mainuserusername,mainuser.ID as mainuserid,mainuser.PictureUrl as mainuserpictureurl,
c.ID as commentID,c.PhotoID as commentphotoid,c.OutputMessage,c.CommentDate,
t.ID as tagID,t.PhotoID as tagphotoid,t.UserID,t.TextTag,t.LeftLocation,t.TopLocation,
u.ID as userid,u.Username,u.FirstName,u.LastName,u.PictureUrl
from albums a
left join photos p on a.ID = p.AlbumID
left join users mainuser on mainuser.ID = p.UserID
left join comments c on c.PhotoID = p.ID
left join tags t on t.PhotoID = p.ID
left join users u on u.ID = c.CommentBy
where a.AlbumAutoID = 3
order by p.DateUploaded desc;

php mysql left join where clause error

With the following tables
posts
id
post_id
user_id
comments
id
post_id
comment_id
user_id
deleted
replies
id
post_id
reply_id
user_id
deleted
I am trying to get every comment and reply from each post.post_id and post.user_id='x' and the comment or reply is not deleted(0)
this is what i have tried
SELECT *
FROM posts p
LEFT JOIN comments c ON p.id=c.post_id
LEFT JOIN replies r ON p.id=r.post_id
WHERE p.user_id=$user_id
&& c.deleted='0' && r.deleted='0'
which does not work...
You need to put the deleted check into the join clause. This should do it:
SELECT *
FROM posts p
LEFT JOIN comments c ON c.post_id = p.post_id AND NOT c.deleted
LEFT JOIN replies r ON r.post_id = p.post_id AND NOT r.deleted
WHERE p.user_id = $user_id
Note: Not sure if c.post_id joins to p.id or p.post_id - chenge the on clause as required
A post may have comments or not. Use LEFT JOIN instead of INNER JOIN.
A post may have replies or not. Use LEFT JOIN instead of INNER JOIN in that join too.
When LEFT JOIN is used, a condition like WHERE comments.deleted = 0 that includes a field (from the right table (comments) in the LEFT JOIN), the LEFT JOIN is cancelled. So, we should put this condition in the ON clause and not in the WHERE.
SELECT *
FROM posts p
LEFT JOIN comments c
ON p.post_id = c.post_id
AND c.deleted = 0
LEFT JOIN replies r
ON p.post_id = r.post_id
AND r.deleted = 0
WHERE p.user_id = $user_id
Thinking more clearly, the above will show what the question describes but in cases with say, 4 comments and 3 replies, 12 rows will be returned (3x4). Which is probably not wanted. The following 2nd try does not have such issue.
I don't see a post.text or comment.text or reply.text in the tables but anyway, you'll get the idea. You can remove the 3 text lines if not appropriate.
( SELECT p.post_id AS post_id
, 0 AS type
, p.post_id AS id
, p.text AS text
FROM posts p
WHERE p.user_id = $user_id
)
UNION ALL
( SELECT p.post_id AS post_id
, 1 AS type
, c.comment_id AS id
, c.text AS text
FROM posts p
JOIN comments c
ON p.post_id = c.post_id
WHERE p.user_id = $user_id
AND c.deleted = 0
)
UNION ALL
( SELECT p.post_id AS post_id
, 2 AS type
, r.reply_id AS id
, r.text AS text
FROM posts p
JOIN replies r
ON p.post_id = r.post_id
WHERE p.user_id = $user_id
AND r.deleted = 0
)
ORDER BY post_id
, post_type
, id
The 0,1,2 stand for post, comment, reply.