How to get multiple data from different relational table in mysql - mysql

I have 3 relational tables : users, posts, and reposts.
In reposts table, I have fields: user_id (the user who reposted the post) and, post_id.
In posts table, I have fields: id, posts, and user_id.
In users table, I have field: id and first_name.
Here are what the data I wanted to get:
The post
The original user who posted
The reporter or the user who reposted the post.
So far i only have this query:
SELECT
p.post,
u.first_name as 'Retweeter'
FROM reposts r
LEFT JOIN users u
ON u.id = r.user_id
LEFT JOIN posts p
ON p.id = r.post_id
In that code I can get the post and the user who reposted the post. But how can I get the original user or the details of the original user who posted the post, using the post_id field from the reposts table?
Thank you very much!

you need one more join on users table for getting original poster name
SELECT
ou.first_name originalPoster,
p.post,
u.first_name as 'Retweeter'
FROM reposts r
LEFT JOIN users u
ON u.id = r.user_id
LEFT JOIN posts p
ON p.id = r.post_id
LEFT JOIN users ou
on p.user_id = ou.id

You have to join users twice, once against posts and once against reposts. If you want to include posts that haven't been reposted, you should start the FROM clause with posts and then do the left joins.
SELECT p.post,
up.first_name,
urp.first_name
FROM posts p
LEFT JOIN users up
ON up.id = p.user_id
LEFT JOIN reposts rp
ON rp.post_id = p.id
LEFT JOIN users urp
ON urp.id = rp.user_id;

Related

select all posts with different post id in mysql

SELECT *
FROM post p
JOIN user u ON p.user_id = u.id
JOIN friendships f ON f.friend_id = u.id
WHERE f.user_id = 1 OR u.id = 1
ORDER BY p.created_at DESC;
working on a projects where I'm trying to get all the post of the user as well as the user currently on.
So far i have this query working but is giving me duplicate posts of users.id = 1
is a user self join many to many where each user become friends and each user has their posts
The problem is probably because you select all columns from all tables involved.
Now for every new friendship with friend_id=1 you will receive a new record, with post duplicated. I guess you need:
select distinct p.*

MySQL not null in left join condition

My query looks like:
SELECT *
FROM users U
LEFT JOIN posts P ON P.userId = U.id AND P.userId IS NOT NULL;
Why the query also return result where userId is null ?
I know that for my needs I can use INNER JOIN to get only posts related to user but is so strange that LEFT JOIN support multiple conditions, but not work with NOT NULL conditions.
This is because "posts" does not contain the null-values and hence they can´t be filtered at that stage. The Null-values are only generated trough the join, when the server can´t find a corresponding row on the right table. So just put the not null in the where clause and it will work:
SELECT * FROM users U LEFT JOIN posts P ON P.userId = U.id WHERE userId IS NOT NULL;
(EDIT: You should use an inner join for productive work though, as it is the proper way and will give you much greater performance.)
You can also see all users who don´t have posts by inverting that:
SELECT * FROM users U LEFT JOIN posts P ON P.userId = U.id WHERE userId IS NULL;
You are outer joining the posts table. This means for every users record that has no match in posts you still get this record with all posts columns null.
So say you have a users record with userid = 5 and there is no posts record with id = 5.
ON P.userId = U.id AND P.userId IS NOT NULL
The two combined conditions are not met (there is no record with userid 5), so you get the users record with all posts columns set to null in your results.
Maybe you are simply looking for an inner join? All users records with their posts data?
This query:
SELECT *
FROM users U LEFT JOIN
posts P
ON P.userId = U.id AND P.userId IS NOT NULL;
Returns all rows in the users as well as all columns from posts, regardless of whether or not they match. This is true, regardless of whether the ON clause evaluates to TRUE or FALSE.
What you want is a WHERE. In addition, you should only select the columns from users:
SELECT u.*
FROM users U LEFT JOIN
posts P
ON P.userId = U.id
WHERE P.userId IS NOT NULL;
Note that you can also accomplish this using NOT IN or NOT EXISTS.
Because the LEFT JOIN must return every row from the left table by it's definition. The raw may be augmented with the data of the right table depending on the ON clause evaluation. So the following code must return a row.
select u.*, p.*
from (
select 1 as id
) u
left join (
-- no data at all
select 2 as id where 1=2
) p on 3 = 4 -- never is true
Try this
SELECT * FROM users U LEFT JOIN posts P ON P.userId = U.id
SELECT * FROM users U LEFT JOIN posts P ON P.userId = U.id where P.userId IS NOT NULL;
IS NOT NULL WITH JOINS
SELECT * FROM users
LEFT JOIN posts ON post.user_id = users.id
WHERE user_id IS NOT NULL;

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 join with 2 Tables and 2 join

I have 2 tables:
posts: userid, lastuserid
users: id, name
I need to join posts.userid = users.id and posts.lastuserid = users.id to get username and lastusername.
My query did as below:
SELECT posts. * , users.name, vUsers.name
FROM posts
INNER JOIN users ON users.id = posts.userid
INNER JOIN Users ON vUsers.id = posts.lastuserid
Is there any other (better) way to do this?
Your query is probably correct. I would encourage you to use table aliases that are abbreviations for the things you are looking for:
SELECT p. * , u.name as username, l.name as lastusername
FROM posts p INNER JOIN
users u
ON u.id = p.userid INNER JOIN
users l
ON l.id = p.lastuserid;
Your query has something called vUsers, which is not defined.

mysql query: display all entries from guestbook_comments for a specific owner_id

I need some help with query from multiple tables.
My database:
I have following tables:
1. users (user_id, user_name, ..) //user_name is unique.
2. guestbook_comments(owner_id, comment_author_id, comment ..)
3. profile_photo(profile_photo_id, user_id, path)
My problem:
I want to build a following query:
I have url like guestbook.php?user=sudeep. So i get user_name by $_GET['user']; user_name is unique (in the users table).
I want to display all entries from guestbook_comments for a specific owner_id (but i only know user_name, so i will need to find user_id from users table).
For each of the comment_author_id in guestbook_comments table, I want to get the his user_name from table users and path from profile_photo table.
My approach:
First I join users and guestbook_comments table to get all guestbook comments for a specific user_id. Then In the while loop I join users and profile_photo table to get user_name and photo path respectively.
I highly doubt if my approach is any efficient. Can you tell me if there is a right way to do that?
$sql = "SELECT u.user_id, g.owner_id, g.comment_author_id
FROM guestbook g
INNER JOIN users u ON u.user_id = g.owner_id
WHERE u.user_name = $user_name";
while($row = mysql_fetch_array( $result )) {
$author_id = $row['comment_author_id'];
$sql = "SELECT u.user_name, p.path
FROM profile_photo p
INNER JOIN users u ON u.user_id = p.user_id
WHERE u.user_id = $author_id;
//display comment text from guestbook, user_name from users, and photo from profile_photo
}
Am I missing something, or could you combine both joins at once and get all the data with 1 call to the database, rather than 2 calls per user?
$sql = "SELECT u.user_id, g.owner_id, g.comment_author_id, p.path
FROM guestbook g
INNER JOIN users u ON u.user_id = g.owner_id
INNER JOIN profile_photo p on u.user_id = p.user_id
WHERE u.user_name = $user_name";
Try a single query:
SELECT u.user_id, g.owner_id, g.comment_author_id, g.comment_text, c.user_name, p.path
FROM users u
LEFT JOIN guestbook g
ON u.user_id = g.owner_id
LEFT JOIN users c
ON c.user_id = g.comment_author_id
LEFT JOIN profile_photo p
ON p.user_id = g.comment_author_id
WHERE u.user_name = $user_name
From user, find guestbook entries, find commenters, find commenters' photos