Friend Table with mysql - 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

Related

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

How to write mysql query to achieve the following type of join (Join based on value of a column )

Table users:
id----email
1-----s#s.com
2-----p#p.com
Table user_buddies
id-----user_id----buddy_id----status enum('accepted','pending')
1------1----------2-----------pending
Suppose I am querying with respect to user 2 then I want to get user 2 email. If I am querying with respect to user 1 then I want to get user 1 email.
The below query is always returning empty rows.
SELECT
users.email,
ub1.*, ub2.*
FROM
users
JOIN user_buddies ub1 ON users.id = ub1.user_id
JOIN user_buddies ub2 ON users.id = ub2.buddy_id
WHERE
users.id = 1;
Can anyone please help me in this?
Thank you.
Expected result:
email-----user_id-----buddy_id-----status
s#s.com --1-----------2------------pending (If queryed on user 2)
p#p.com---1-----------2------------pending (If queried on user 1)
Context:
When user1 sends request to user2 only one row is added to the user_buddies table with status=pending. So, both for user1 and user2 buddy list is created using same row. So if queried against user2 email needed is user2's.
You may check the following query:
SELECT
users.email,
ub1.user_id,
ub1.buddy_id,
ub1.`status`
FROM
users
JOIN user_buddies ub1 ON users.id = ub1.user_id OR users.id = ub1.buddy_id
WHERE users.id = 2;
SQL FIDDLE DEMO
Result:
email user_id buddy_id status
p#p.com 1 2 pending (if queried on users.id = 2)
s#s.com 1 2 pending (if queried on users.id = 1)
EDIT:
SELECT
(
SELECT
u.email
FROM users u
WHERE u.id =
IF (
users.id = ub1.user_id,
ub1.buddy_id,
ub1.user_id
)
) AS buddyEmail,
ub1.user_id,
ub1.buddy_id,
ub1.`status`
FROM
users
INNER JOIN user_buddies ub1 ON users.id = ub1.user_id
OR users.id = ub1.buddy_id
WHERE users.id = 2;
Check this fiddle of this new query
SELECT 'Userid' querysource, u.id, u.email, ub.*, u1.EMAIL AS Buddyemail
FROM #users u
JOIN #user_buddies ub ON u.id = ub.user_id
JOIN #users u1 ON u1.id = ub.BUDDY_ID
WHERE u.id = 1
UNION
SELECT 'Buddyidid', u.id, u.email, ub.*, u1.email AS Buddyemail
FROM #users u
JOIN #user_buddies ub ON u.id = ub.buddy_id
JOIN #users u1 ON u1.id = ub.user_ID
WHERE u.id = 1

SQL query to link two tables returning error

I have two tables as follows
user [ ID , username ]
relationship [ user1_id(FK) , user2_id (FK) , status ]
I am trying to get the username by using either user1_id or user2_id where the status = 1 from relationship table. user1_id and user2_id are both IDs from the user table. The following query is failing and I am not sure where it's going wrong.
SELECT
U.username,
(R.first_user_id, R.second_user_id AS friends)
FROM
user U,
`relationship` R
WHERE (R.`first_user_id` = {$userID} OR R.`second_user_id`)
AND (`status` = 1 AND U.ID = friends)
returns both names of users in a relationship with a status of 1.
this also assumes that if a relationship record exists, both users must be in the user table.
SELECT U1.UserName, U2.username
FROM Relationship R
INNER JOIN USER U1
on R.User1_ID = U1.user_ID
INNER JOIN USER U2
and R.User2_ID = U2.user_ID
WHERE R.Status=1
It looks like you may be trying to get the usernames of all users that have a relationship with a certain specified user, regardless of the order of user IDs in the relationship record. That could be this:
SELECT
U.username,
U.first_user_id,
FROM
user U
JOIN `relationship` R
ON R.first_user_id = U.ID
WHERE
(R.`second_user_id` = {$userID})
AND (`status` = 1)
UNION ALL
SELECT
U.username,
U.second_user_id,
FROM
user U
JOIN `relationship` R
ON R.second_user_id = U.ID
WHERE
(R.`first_user_id` = {$userID})
AND (`status` = 1)
If that produces duplicates (or could do) and you don't want it to do, then change the UNION ALL to a straight UNION.
I have succeeded based on xQbert answer:
SELECT
U1.username,
U2.username
AS user_friend
FROM
Relationship R
INNER JOIN
user U1
ON
R.first_user_id = U1.ID
INNER JOIN
user U2
ON
R.second_user_id = U2.ID
WHERE (R.`first_user_id` = {$userID} OR R.`second_user_id` = {$userID})
AND `status` = 1

Mysql join from multiple tables

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

Select the users are not friend of a specific user

Hi, I have these two tables: users and friends (friend_status = 1 means the request is sent, friend_status = 2 means they are friends). Now I want to select all users are not friend of a specific user. How to do?
Assuming the current user is 1. I tried this SQL. It works but it's too long and slow. The first selects all users sent request to user1 but not accepted. The second selects all users receive request from user1. The third and the fourth selects all users is not in "friends" table.
SELECT user_id, name, email
FROM
(
SELECT user_id, name, email
FROM users u INNER JOIN friends f ON u.user_id = f.sender
WHERE f.receiver = 1 AND friend_status <> 2
UNION
SELECT user_id, name, email
FROM users u INNER JOIN friends f ON u.user_id = f.receiver
WHERE f.sender = 1 AND friend_status <> 2
UNION
SELECT u.user_id, u.name, u.email
FROM users u LEFT JOIN friends f ON u.user_id = f.sender
WHERE f.receiver IS NULL
GROUP BY user_id
UNION
SELECT u.user_id, u.name, u.email
FROM users u LEFT JOIN friends f ON u.user_id = f.receiver
WHERE f.sender IS NULL
GROUP BY user_id
) T
GROUP BY user_id
Update: Add a pic.
SELECT
a.user_id,
a.name,
a.email,
b.status IS NOT NULL AS friend_status
FROM
users a
LEFT JOIN
friends b ON
a.user_id IN (b.sender, b.receiver) AND
1 IN (b.sender, b.receiver)
WHERE
(b.friend_id IS NULL OR b.status <> 2) AND
a.user_id <> 1
You had asked a question previously here - "Select users who aren't friends with anyone", and I provided an answer which utilized a LEFT JOIN.
Building off of that, to select users who aren't friends with a specific user, we just simply need to add that specific user's ID to the LEFT JOIN condition (1 IN (b.sender, b.receiver).
Minor Edit: Unless the user can friend him/herself, it wouldn't make sense to also select the user who we're selecting against!! So I added WHERE a.user_id <> 1.
Assuming you want to perform the query on user_id 1:
SELECT user_id, name, email
FROM users AS u
WHERE NOT EXISTS (SELECT * FROM friends AS f
WHERE (f.sender = u.user_id AND f.receiver = 1 AND f.friend_status = 2)
OR (f.sender = 1 AND f.receiver = u.user_id AND f.friend_status = 2)
)
AND u.user_id <> 1
The subquery fetches all the established friendship relationship in which user 1 is either the sender or the receiver. The outer query selects all users for which no such relationship exists. The user with ID 1 is excluded from the query using the last line, as, even if he cannot be friend with himself, I suppose that he should not appear in the final query result.
You may be able to simplify this by using something like this:
SELECT user_id, name, email
FROM
(
SELECT u.user_id, u.name, u.email
FROM users u LEFT JOIN friends f ON u.user_id = f.sender
WHERE IFNULL(friend_status,0) <> 2
GROUP BY user_id
UNION
SELECT u.user_id, u.name, u.email
FROM users u LEFT JOIN friends f ON u.user_id = f.receiver
WHERE IFNULL(friend_status,0) <> 2
GROUP BY user_id
) T
GROUP BY user_id
The IFNULL function returns the value of the first parameter, replacing NULLs with the value of the value second parameter. In this case it means that friend_status will be treated as 0 if there is no matching friend in the friends table, which allows you to reduce the number of selects in the UNION by half.
Try this query
select
u.user_id,
u.name,
u.email,
ifnull(f.friend_status,0) as Relation
from users as u
left join friends as f
on f.sender = u.user_id
where u.user_id not in(select
sender
from friends
where sender = 1)
Here sender = 1 means the user id = 1. You can pass user id to restrict this condition. Also status 0 means he is not friend. and 1 , 2 , 3 are according to your rules