I am writing a chat database.
If users are friends, then they have each other in the friends table, like user 1 and 2 or 1 and 5 in my table(see link).
But I want to find out who sent the application as a friend. In this case, only one person stores the id of another person, like user 1 who sent request for user 7.
I have table:
(only 3 column: idfriend, iduser, friend_id)
How i can select user id (friend_id) who sent request for friend?
If i chose user 1, then my sql must return this friend request:
|friend_id|
7
i try this:
select friend.friend_id from friend inner join friend as friends on
friend.iduser != friends.friend_id and friends.iduser != friend.friend_id
and friend.iduser != friends.iduser and friend.friend_id !=
friends.friend_id where friend.iduser = 1
but this select 7,2 and 5. Need only 7
With NOT EXISTS:
select t.friend_id from friend t
where t.iduser = 1
and not exists (
select 0 from friend
where iduser = t.friend_id and friend_id = t.iduser
)
See the demo.
Results:
| friend_id |
| --------- |
| 7 |
Hopefully this is the solution you are looking for:
select t1.iduser, t1.friend_id
from friends t1
where t1.friend_id not in
(
select t2.iduser
from friends t2
where t2.friend_id = t1.iduser
)
Related
So I have a list of ids(userId's) that was found using a sql command that I want to check with my friends table to see if they are indeed friends with myself, a userid I will provide with, and have a column that will represent if they are and also group them if they are my friend and not my friend.
Example:
List of userids:
1
2
3
Friends table:
-------
userId *the userid sending a friend request*
friendId *the userid receiving the friend request*
relationshipId *an unique id for the relationship*
initiated_by *the userid initiating the friend request*
status *whether or not the users are friends 'friends' or 'pending'*
sample friends table data
I tried creating a subquery that would first get the list of ids I want, and then tried to compare it with my friends table but couldn't quite put it together because the friends table is not bidirectional, meaning each row represents a relationship between 2 people with a status friends or pending
Use a CASE expression to get the friend of a person (i.e. pick either the userid or the friendid from the friends table).
As of MySQL 8 you can use a WITH clause to get this readable:
with friends_of_user_1 as
(
select case when userid = 1 then friendid else userid end as userid
from friends
where 1 in (userid, friendid)
and status = 'friends'
)
, friends_of_user_2 as
(
select case when userid = 2 then friendid else userid end as userid
from friends
where 2 in (userid, friendid)
and status = 'friends'
)
select
userid,
userid in (select userid from friends_of_user_2) as is_friend_of_user_2
from friends_of_user_1;
The same without WITH:
select
userid,
userid in
(
select case when userid = 2 then friendid else userid end as userid
from friends
where 2 in (userid, friendid)
and status = 'friends'
) as is_friend_of_user_2
from
(
select case when userid = 1 then friendid else userid end as userid
from friends
where 1 in (userid, friendid)
and status = 'friends'
) friends_of_user_1;
You can get all friends bidirectional, i.e. (a,b), (b,a), (a,c), (c,a), ... with a UNION query. If it is guaranteed that there exists no (b,a) in the table when there exists (a,b), then you can use UNION ALL, otherwise use UNION.
Then you can aggregate per user and see whether they are friends with user 1 and/or user 2:
with all_friends as
(
select userid as userid1, friendid as userid2 from friends status = 'friends'
union
select friendid as userid1, userid as userid2 from friends status = 'friends'
)
select
userid1,
sum(userid2 = 2) > 0 as is_friends_with_user_2
from all_friends
group by userid1
having sum(userid2 = 1) > 0 -- is friends with user 1
Use the alias of Friends a second time to get the reciprocal relationship
SELECT A.Name,...
FROM Users A
JOIN friends FA ON A.userID = FA.userID
LEFT JOIN friends FB ON FA.friedID = FB.userID
JOIN Users B on FB.userID = B.userID
...
So FA is the friends of A and FB is the friend relationship of B back to A.
I have two tables as follows:-
Users (Table1)
id name email passs
1 u1 uemail1 pass1
2 u2 uemail2 pass2
3 u3 uemail3 pass3
4 u4 uemail4 pass4
Messages (Table2)
mess_id sender receiver message_text send_time
1 1 2 text1 2019-03-25 09:39:05
2 1 2 text2 2019-03-30 15:10:54
3 1 3 text3 2019-03-30 15:11:59
4 1 4 text4 2019-03-30 15:12:48
5 1 4 text5 2019-03-30 15:13:53
6 4 1 text6 2019-04-09 09:26:53
The logged in user is u1 and i want to get the latest conversation which is the 6th one okay.
Now what i want is to find the latest conversation of u1 and with whom and then find the details from users table of other user with whom u1 had the latest conversation
I hope you got my question and it's clear to everyone.
How can i do all this is 1 query
The result will be the other user's detail like this in the above case the user will be u4
id name email passs
4 u4 uemail4 pass4
So far i have tried this but not getting the result what i wanted
select name from users where id=(select receiver_id,sender_id from messages where receiver_id or sender_id=1 order by send_time desc limit 1)
One way is to determine the other user id in a Derived Table, and then join this to the user table, to get the user details.
SELECT
u.*
FROM
user AS u
JOIN
(
SELECT
IF(sender <> 1, sender, receiver) AS other_user /*Logged-in User Id is mentioned here */
FROM messages
WHERE sender = 1 OR receiver = 1 /*Logged-in User Id is mentioned here */
ORDER BY send_time DESC LIMIT 1 /*Get the latest message row */
) AS dt ON dt.other_user = u.id
IF(sender <> 1, sender, receiver) determines the other user id. If sender is not 1 (logged-in user), then we consider sender as the other user, else receiver. This is based on a (mostly valid) assumption that the sender and receiver will always be different values.
Here's a somewhat complex but very general way of solving the problem. It finds the maximum send/receive time for each user in a derived table, then JOINs that to the messages table to find the other user related to that message, and then JOINs that again to the users table to find that user's details. The user of interest is specified in the WHERE clause at the end of the query.
SELECT u2.*
FROM users u1
JOIN (SELECT user, MAX(send_time) AS send_time
FROM (SELECT sender AS user, MAX(send_time) AS send_time
FROM messages
GROUP BY sender
UNION
SELECT receiver, MAX(send_time)
FROM messages
GROUP BY receiver) mt
GROUP BY user) mt ON mt.user = u1.id
LEFT JOIN messages m1 ON m1.sender = mt.user AND m1.send_time = mt.send_time
LEFT JOIN messages m2 ON m2.receiver = mt.user AND m2.send_time = mt.send_time
JOIN users u2 ON u2.id = COALESCE(m1.receiver, m2.sender)
WHERE u1.id = 1
Output:
id name email passs
4 u4 uemail4 pass4
Demo on dbfiddle
Currently I'm using the following SQL query to find out what rooms a user is in, and what other users are in those rooms:
SELECT r1.room, r2.user
FROM
rooms r1 JOIN rooms r2 ON r2.room = r1.room
WHERE r1.user='foobar'
Sample rooms table:
room | user
a | user1
b | user1
c | user1
a | user2
a | user3
a | user4
I would like to limit the other users in same rooms part to 50 users returned per room, but not limit the amount of rooms. Is this possible in a single query?
Example response for user1 (let's say I want to limit it to 3 users returned per room):
a, user1
a, user2
a, user3
b, user1
c, user1
It is possible, with some interesting use of parameters, and nesting of derived tables:
SET #user = 'user1';
SELECT
calclist.room,
calclist.user
FROM
(
SELECT
joinedlist.room 'room'
, joinedlist.user 'user'
, IF(joinedlist.room=#room, #rownum:=#rownum+1, #rownum:=1) 'count'
, (#room:=joinedlist.room) dummy
FROM
(
SELECT
roommate_rooms.room,
roommate_rooms.user
FROM
rooms user_rooms
INNER JOIN rooms roommate_rooms
ON user_rooms.room = roommate_rooms.room
WHERE user_rooms.user = #user
ORDER BY
roommate_rooms.room,
roommate_rooms.user
) joinedlist
JOIN (SELECT #rownum:=1) rn
) calclist
WHERE calclist.count <= 3
;
It can cope with the user being in any number of rooms, with or without any roommates; any number of other users who do not share any rooms; and it can cope with the data being entered 'out of order'. Worked example on SQL Fiddler; and credit to Jimmy's Blog for how to use the dynamic parameters to do the counting.
SELECT a.*
FROM rooms a
WHERE
(
SELECT COUNT(*)
FROM rooms b
WHERE a.room = b.room AND
a.user >= b.user
) <= 3
ORDER BY a.Room, a.User
SQLFiddle Demo
Here are my two tables:
TABLE: friends
'id' // primary id, auto increment
'uid' // user id who sent friend request
'fid' // friend id who received friend request
'status' //status of friendship, 1=active
.
TABLE: messages
'id' // message id (primary id), auto increment
'uid' // user who sent the message
'fid' // friend who received the message
'time' // time when the message was sent
'status' // status of message, read or unread.
I want to show only the list of friends I have sent messages to or received messages from ordered by the time of last message sent (by the friend or by me). One friend should be listed only once. How am I supposed to do that?
I want to show only the list of friends I have sent messages to or
received messages from ordered by the time of last message sent (by
the friend or by me).
Try this:
SELECT DISTINCT friends.id
FROM messages m
INNER JOIN
(
SELECT uid id FROM friends WHERE status = 1 AND fid = myuserid
UNION ALL
SELECT fid FROM friends WHERE status = 1 AND uid = myuserid
) friends ON m.fid = friends.id OR m.uid = friends.id
However, if there is a users table, you can do this:
SELECT
senders.name 'From',
recievers.name 'To',
m.id,
m.body,
m.messagetime,
m.status
FROM messages m
INNER JOIN
(
SELECT uid id FROM friends WHERE status = 1 AND fid = 1
UNION ALL
SELECT fid FROM friends WHERE status = 1 AND uid = 1
) friends ON m.fid = friends.id OR m.uid = friends.id
INNER JOIN users senders ON m.uid = senders.id
INNER JOIN users recievers ON m.fid = recievers.id
WHERE m.uid = 1
OR m.fid = 1
ORDER BY m.messagetime ASC OR DESC
SQL Fiddle Demo
For instance, this will give you:
| FROM | TO | ID | BODY | MESSAGETIME | STATUS |
--------------------------------------------------
| Me | B | 1 | hiiii | 2012-12-01 | 1 |
| c | Me | 7 | sadfds | 2012-12-01 | 1 |
| Me | B | 8 | ddd | 2012-12-10 | 1 |
How this query works?
The query:
SELECT uid id FROM friends WHERE status = 1 AND fid = myuserid
UNION ALL
SELECT fid FROM friends WHERE status = 1 AND uid = myuserid
will give you the list of your friends, a friend of yours is either:
A user sent a friendship request to you and accepted, or
A user you send him a friendship request and he accept it.
Thats why I used a UNION ALL with fid = your user id, and I also assumed that status = 1 means that the friendship request is accepted.
These are your friends. Then, to get the list of friends you have sent messages to or received messages from, we have to join this result set with the messages table. But to get the messages sent to you or the messages sent by you, we have to choose the join condition m.fid = friends.id OR m.uid = friends.id. Thats it.
I've been trying to figure out for a week or so, how I can make a proper friendship system in CakePHP. I've read this and this thread but I can't get it to work.
I've read a lot more threads regarding this, but nobody seems to have a proper example.
I currently have a table users (id, username, password, e-mail etc.) and a table friendships (id, user_to, user_from, status).
Step 1 - Friendship request
If a user does a friendship request, then a row is inserted with the requesting user_id and the user_id of the user from whom the friendship is request, so it could look like:
id | user_from | user_to| status
1 | 1 | 2 | 0
This way I can easily show pending friends of user_id = 2, by selecting all records where user_to = 2
Step 2 - Confirm friendship
I've set it up so that user_id 2 now sees that user_id 1 wants to become friends, if he clicks the confirmation link, the status will be changed to 1, see below
id | user_from | user_to| status
1 | 1 | 2 | 1
I created all kinds of checks so the row stays unique.
Step 3 - Show friends
I thought this would be easy, if I want to show the friends of user_id = 1 then I just do a select with user_from = 1 OR user_to = 1, however this doesn't work.
User_id 1 can be a requester but can also be requested, so a JOIN will show strange results.
Does anyone know a solution? I'm happy to rebuild the entire system if I'm not doing the entire thing right! Any hints in the right direction are welcome as well...
Here is my solution : the difficulty lies in the correct request because friend requests can be crossed (if A asks B or B asks A will be stored the opposite way in the "to" and "from" fields of the table). Lets do it like that and user UNION and aliases to get friends from any user independently of the relation table bellow.
The [friends] table (relation): to|from|statut(pending,confirmed)
"to" and "from" > foreign_keys constraint to a [users] table
The request below always gives the wanted results ! (replace %d by the user ID or user Id in the SESSION
SELECT
users.userNickname,
friends.to AS friendUser,
friends.from AS currentUser,
friends.statut
FROM
users
INNER JOIN
friends
ON
users.userId = friends.to
WHERE
friends.from = '%d'
UNION
SELECT
users.userNickname,
friends.from AS friendUser,
friends.to AS currentUser,
friends.statut
FROM
users
INNER JOIN
friends
ON
users.userId = friends.from
WHERE
friends.to = '%d'
You can find friend requests to ID = 1 this way:
select * from Users u1 where u1.user_to = 1 and u1.user_from not in (select u2.user_to
from Users u2 where u2.user_from = u1.user_to)
You can find friend requests from ID = 1 this way:
select * from Users u1 where u1.user_from = 1 and u1.user_to not in (select u2.user_from
from Users u2 where u2.user_to = u1.user_from)
You can find mutual friendships of ID = 1 this way:
select * from Users u1 where ((u1.from = 1) or (u1.to = 1)) and 0 < (select count(*) from
Users u2 where u1.from = u2.to and u1.to = u2.from)
This code was not tested, but you get the idea.