Mysql join from multiple tables - mysql

I have 3 tables
friends
posts
members
friends
========
id, to, from (user_id's), status
there are 3 status's -1 = denied, 0 = no response/new, 1 = accepted
posts
=======
p_id, user_id (same as member_id), text
members
========
member_id, f_name, l_name
If like to select the text from the post in 'posts' combine it with the users name from 'members' and only display posts where the user_id is in the 'friends' table.
I would like to know if it can be done, I've tried an IN () statement in my query which worked, but it creates a new problem with generating the csv inside the IN (). I'd perfer to do this through mysql, but if it can't be done I may use a global variable to store friend data (but then it will not be upto date or will have to be refreshed when a user gets a new friend).

As I understand it, you want to find the name and posts of all your friends, not any friend that's in the friend table at all...?
Your own user id being in $myId, this should do it (newest posts first);
EDIT: Added status check for friends
SELECT m.f_name, m.l_name, p.`text`
FROM members m
JOIN posts p
ON m.member_id = p.user_id
JOIN friends f
ON f.`to` = m.member_id OR f.`from` = m.member_id
WHERE (f.`from` = $myId OR f.`to`= $myId)
AND f.`status` = 1 AND m.member_id <> $myId
ORDER BY p.p_id DESC

Try this :
SELECT p.text,m.f_name,m.l_name FROM posts p
LEFT OUTER JOIN members m ON p.user_id=m.member_id
where p.user_id in(select id from friends);
OR
SELECT p.text,m.f_name,m.l_name FROM posts p
LEFT OUTER JOIN members m ON p.user_id=m.member_id
INNER JOIN friends f on p.user_id=f.id

If I understand correctly, you have a user_id and you want all the posts authored by "friends" of that user. This query starts at posts, joins that to friends (where the author is the "destination" of the friendship) (at which point the WHERE clause will filter out any non-friend posts), and then joins in members to fill out the author's name info.
SELECT
posts.p_id
posts.text,
CONCAT(members.f_name, " ", members.l_name)
FROM
posts
JOIN friends ON posts.user_id = friends.to
JOIN members ON posts.user_id = members.member_id
WHERE
friends.from = ?
GROUP BY posts.p_id

I added a subquery to get all your friends since I assumed that if you have these records
Friends
==================================
ID TO FROM STATUS
==================================
1 1 2 1
2 3 1 1
and your member_id = 1, your friends are 2, 3. right?
SELECT b.f_name,
b.L_name,
c.`text`
FROM
(
SELECT `to` friendID
FROM friends
WHERE `status` = 1 AND
`from` = ? -- change this to your ID
UNION
SELECT `from` friendID
FROM friends
WHERE `status` = 1 AND
`to` = ? -- change this to your ID
) a INNER JOIN members b
ON a.friendID = b.member_ID
LEFT JOIN posts c
ON a.friendID = c.user_id

Related

MySQL Column 'id' in IN/ALL/ANY subquery is ambiguous

I am trying to do a search functionalities that involves three tables.
Searching for users and returning wheather the user id 1 is a friend of the returned users. Also The returned users is being filtered from a third table where it checks tag of that users.
So I can say, "Return users who has tag 'Programming', 'Php'
in userinterests table and also if the returned user is a friend of usr id 1 or not "
I am trying to use the bellow query but getting Column 'id' in IN/ALL/ANY subquery is ambiguous
If I remove the left join then it works.
SELECT n.id, n.firstName, n.lastName, t.id, t.tag, t.user_id, if(id in (
SELECT u.id as id from friends f, users u
WHERE CASE
WHEN f.following_id=1
THEN f.follower_id = u.id
WHEN f.follower_id=1
THEN f.following_id = u.id
END
AND
f.status= 2
), "Yes", "No") as isFriend
FROM users n
LEFT JOIN userinterests t on n.id = t.id
WHERE t.tag in ('Programming', 'Php')
Thank you for your time :)
Qualify all your column names. You seem to know this, because all other column names are qualified.
I'm not sure if your logic is correct, but you can fix the error by qualifying the column name:
SELECT . . .
(CASE WHEN n.id IN (SELECT u.id as id
FROM friends f CROSS JOIN
users u
WHERE CASE WHEN f.following_id=1
THEN f.follower_id = u.id
WHEN f.follower_id=1
THEN f.following_id = u.id
END
) AND
f.status= 2
THEN 'Yes' ELSE 'No'
END) as isFriend
. . .
This is the way I will go for your approach:
1) I used INNER JOIN instead of LEFT JOIN for skip users that are not related to tags: Programming and Php.
2) I replaced the logic to find the set of friends related to user with id equal to 1.
SELECT
n.id,
n.firstName,
n.lastName,
t.id,
t.tag,
t.user_id,
IF(
n.id IN (SELECT follower_id FROM friends WHERE status = 2 AND following_id = 1
UNION
SELECT following_id FROM friends WHERE status = 2 AND follower_id = 1),
"Yes",
"No"
) AS isFriend
FROM
users n
INNER JOIN
userinterests t ON n.id = t.id AND t.tag IN ('Programming', 'Php')
Just curious, whats is the meaning of status = 2 ?

Sql query correction one to many tables

I have two tables one is users and second is user_education.One users can have more than one education listing so i want to get the latest user education listing
users
===============
1-id
2-email
member_experience
==============
1-id
2-user_id
3-designation
user id 1 has 4 enteries in user_education so i want to get the last record enter designation of the user
original full query is like this
SELECT u.id,u.name,u.gender,u.email,file_managed.file_name,file_managed.file_path
from users as u
INNER JOIN member_experience on (SELECT uid FROM member_experience where member_experience.uid=u.id ORDER BY id DESC LIMIT 1)=u.id
LEFT JOIN file_managed on file_managed.id= u.fid
where u.user_type ='individual' AND u.gender='male'
"INNER JOIN member_experience on (SELECT uid FROM member_experience where member_experience.uid=u.id ORDER BY id DESC LIMIT 1)=u.id "
this portion has problem as users has many record in member_experience table but i want to get only one which is latest.
thanks
Devolve the acquisition of the last record to the where statement.
drop table if exists member_experience;
create table member_experience(id int auto_increment primary key, userid int);
insert into member_experience (userid) values
(1),(2),(1);
select * from member_experience
SELECT u.id,m.id
from users as u
join member_experience m on m.userid = u.id
where m.id = (SELECT max(m.id) FROM member_experience m where m.userid = u.id)
order by u.id
Or if you want to include those with no experience
SELECT u.id,m.id
from users as u
left join member_experience m on m.userid = u.id
where (m.id = (SELECT max(m.id) FROM member_experience m where m.userid = u.id)
or m.id is null)
and u.id < 4
order by u.id

MYSQL compare values from same columns

Okay I tried to look all over stackoverflow, and the closest solution I found is this:
mysql AND clause on same column multiple times
But I can't use statements and "having" syntax won't work because of group by. There MUST be a simple solution to this.
The 2 tables looks like this (simplified):
users:
uid name
1 person 1
2 person 2
3 person 3
categories:
uid value
1 actor
1 musician
2 actor
3 dancer
4 musician
4 dancer
I want to get the uid of those that are 2 values at the same time. For example, I want to get the UID that is an actor AND a musician. Not just one value, but both of them must be required!
First I tried this:
SELECT users.uid, users.name
FROM
users
LEFT OUTER JOIN categories ON users.uid = categories.uid
WHERE (categories.value = 'actor' AND categories.value = 'musician')
GROUP BY u.uid;
This of course does not work since one row can't have 2 values.
Does anyone know a solution?
You can JOIN to the categories table multiple times to get the result:
SELECT users.uid, users.name
FROM users
INNER JOIN categories c1
ON users.uid = c1.uid
INNER JOIN categories c2
ON users.uid = c2.uid
WHERE c1.value = 'actor'
AND c2.value = 'musician';
See SQL Fiddle with Demo
SELECT users.uid, users.name
FROM users
LEFT JOIN categories ON users.uid = categories.uid
WHERE categories.value in ('actor', 'musician')
GROUP BY u.uid, users.name
having count(distinct categories.value) = 2;
Use a having clause
SELECT u.uid, u.name
FROM users u
LEFT OUTER JOIN categories c ON u.uid = c.uid
WHERE c.value = 'actor' OR c.value = 'musician'
GROUP BY u.uid
having count(distinct c.value) > 1
If you really do not want to use having you could try this:
SELECT uid, name
FROM users
WHERE
uid IN (SELECT uid FROM categories WHERE value='actor')
AND uid IN (SELECT uid FROM categories WHERE value='musician')
But there is really nothing wrong with using HAVING ;)

Getting friends update query

I have three tables which are members, friends, and updates. I am trying to develop a query that will grab the updates for users who are friends with a specific user. For example get all the updates from all the friends of member X, USER:
X -> friend_1 > updated picture
-> friend_2 > added friend
-> friend_3 > updated status
Y -> friend_1 > updated picture
-> friend_2 > added friend
-> friend_3 > updated status
FRIENDS
friend_index
friend_id
logged_user_id *
MEMBERS
display_name
id *
UPDATES
update_id
member_id *
friend_id
update_action
So far this is the query that I have currently this gives me the updates of the current user and not the current users friends.
SELECT
U.update_id,
U.update_action,
U.update_hidden,
U.update_time,
U.member_id,
U.friend_id AS friend,
M.id,
M.display_name AS user,
F.friend_id,
F.logged_user_id
FROM member_friends F
JOIN members M
ON M.id = F.logged_user_id
JOIN member_updates U
ON U.member_id = F.friend_id
WHERE U.member_id = :id
ORDER BY U.update_id DESC
Thanks for taking a look.
You are joining the member_update with user.id thus leaving out the friends updates in the first join.
I would begin by selecting all the friends and then joining the member_update table with friends table and not user table
Query:
SELECT
U.member_id,
U.update_action,
FROM members M
JOIN member_friends F
ON M.id = F.logged_user_id
JOIN member_updates U
ON U.member_id = F.friend_id
WHERE M.id = :id
AND U.update_hidden <> 1
ORDER BY U.update_id DESC
Assuming logged_user_id is the user id which has firends friend_id
UPDATES.member_id is the user id to which that update belongs
Try this:
SELECT
U.update_id,
U.update_action,
U.update_time,
U.member_id,
U.id,
F.friend_id,
U.display_name AS user,
F.display_name AS friend
FROM members M
JOIN member_friends F
ON M.id = F.logged_user_id
JOIN member_updates U
ON U.member_id = F.friend_id
WHERE M.id = :id
AND U.update_hidden <> 1
ORDER BY U.update_id DESC

Friend Table with mysql

I am working the friend table with mysql. I want to get friend userid and username form current username.
friend
=======
- id
- uid
- fid
Sample Data
===========
id uid fid
1 1 2
2 3 1
user
====
- id
- username
Sample Data
===========
id username
1 saturngod
2 snow
3 John
My current code is
SELECT `user`.id,`user`.username FROM friend
INNER JOIN User
ON user.id = friend.uid
WHERE friend.fid = ( SELECT `id` FROM `User` WHERE `username`='saturngod')
UNION
SELECT `user`.id,`user`.username FROM friend
INNER JOIN User
ON user.id = friend.fid
WHERE friend.uid = ( SELECT `id` FROM `User` WHERE `username`='saturngod')
It's working. I got the friend list. However, I feel , the sql is so long.
Can I reduce this sql and can we write without UNION in sql ?
You have already joined the tables, so the subselect is not needed.
SELECT u.id,u.username
FROM user u
INNER JOIN friend f ON (u.id = f.uid)
WHERE u.username='saturngod'
UNION ALL
SELECT u2.id,u2.username
FROM user u
INNER JOIN friend f ON (u.id = f.uid)
INNER JOIN user u2 ON (u2.id = f.fid)
WHERE u.username='saturngod'
Or you can do:
SELECT
u.id as user_id
,u.username
,u2.id as friend_id
,u2.username as friendname
FROM user u
INNER JOIN friend f ON (u.id = f.uid)
LEFT JOIN user u2 ON (u2.id = f.fid)
WHERE 'saturngod' = u.username
If you want one row per user you can do:
SELECT
u.id as user_id
,u.username
,GROUP_CONCAT(u2.id) AS friend_ids
,GROUP_CONCAT(u2.username) as friendnames
FROM user u
INNER JOIN friend f ON (u.id = f.uid)
LEFT JOIN user u2 ON (u2.id = f.fid)
WHERE 'saturngod' = u.username <<-- optional
GROUP BY u.id
SELECT CASE WHEN user_id="$id" THEN friend_id ELSE user_id END AS friendID
FROM user_friend WHERE user_id="$id" OR friend_id="$id" order by friendID ASC