MySql query with subqueries - mysql

I'm having trouble trying to make a simple query.
My tables are:
user
+-------+----------+
| id | username |
+-------+----------+
messages
+-------+-------------+------------+--------+
| id | receiver_id | sender_id | text |
+-------+-------------+------------+--------+
I need to get all messages coming from or received from a SEPECIFIC user (knowing his username).
But also I need to get the receiver and sender username.
I used
SELECT * from user U, messages M where (M.sender_id OR M.receiver_id)=(select id from user where username = 'Guy1') group by M.id
This works but now I need their username so I thought about something like:
SELECT * from user U, messages M, (select username as Sender from user U1, messages M1 where M1.sender_id= U1.id)as Sub where (M.sender_id OR M.receiver_id)=(select id from user where username = 'Guy1') group by M.id
but it's not giving me what I need, how can I achieve what I'm trying to do?
In the result I need something like:
+-------+-------------------+------------------+
| text | receiver_Username | sender_Username |
+-------+-------------------+------------------+

I think the following query will get the result you need by joining two times messages table with user table. One for the senders and one for the receivers
SELECT messages.text,sender.username,receiver.username from messages
inner join user as sender on sender.id = messages.sender_id
inner join user as receiver on receiver.id = messages.receiver_id

Maybe I didn't express well, I need to get username of sender_id and username of receiver_id and the text. But only where user is = User1 All these queries you posted doesn't do this – Gabriele Prestifilippo 6 secs ago
Username and Text of sender_id:
SELECT u.username, m.text FROM user AS u
LEFT JOIN messages AS m ON u.id = m.sender_id
WHERE u.username = 'Some_User';
Username and Text of receiver_id:
SELECT u.username, m.text FROM user AS u
LEFT JOIN messages AS m ON u.id = m.receiver_id
WHERE u.username = 'Some_User';
Combined:
SELECT u.username, m.text, x.text FROM user AS u
LEFT JOIN messages AS m ON u.id = m.receiver_id
LEFT JOIN messages AS x ON u.id = x.sender_id
WHERE u.username = 'User1'

SELECT U.username, M.receiver_id, M.sender_id, M.text
FROM user U
LEFT JOIN messages AS M ON U.id = M.sender_id

Related

Adding a extra subquery to MySQL query

So i have 2 tables, users and messages
users table
uid, username
messages table
mid, senderid, receiverid, message, timestamp
The query i have at the moment is retrieving the uid, username and last timestamp of each chat conversation
SELECT DISTINCT
IF (messages.senderid = '5e9b95786a71f8.25790415', messages.receiverid, messages.senderid) as uid,
(SELECT username FROM users WHERE uid = IF (messages.senderid = '5e9b95786a71f8.25790415', messages.receiverid, messages.senderid)) as username,
MAX(messages.timestamp) as last_timestamp
FROM messages JOIN users ON users.uid = messages.senderid WHERE messages.senderid = '5e9b95786a71f8.25790415' OR messages.receiverid = '5e9b95786a71f8.25790415'
GROUP BY 1,2
which outputs below
uid | username | last_timestamp
1 | Developer | 1601826378
2 | BetaTester | 1601826301
What i need to add to this query is the message field which is based on the last_timestamp i have in the output.
How can the query be updated to include the extra message field?
Try this.
select A.uid, C.username, B.timestamp, B.message from (SELECT DISTINCT
IF (messages.senderid = '5e9b95786a71f8.25790415', messages.receiverid, messages.senderid) as uid,
MAX(messages.mid) as max_mid
FROM messages WHERE messages.senderid = '5e9b95786a71f8.25790415' OR messages.receiverid = '5e9b95786a71f8.25790415'
GROUP BY 1) A join messages B on A.max_mid = B.mid join users C on A.uid = C.uid
I'm a little confuse, since you already got last_timestamp why don't just left join message table again.
left JOIN messages m2 on last_timestamp = m2.timestamp and mid = m2.mid
and just select message column
select m2.message

SQL inner join on two colums

If i had two database tables
users -> (id, username)
and
messages -> (msg_id, sender_id, rec_id, text)
and they both joind on users.id = messages.sender_id and also on users.id = messages.rec_id so how i can print out results as follow
msg_id | sender | reciver | text
------------------------------------
1 | david | michael | hello friend
2 | eva | robert | pick me up
I've try this
SELECT users.*, messages.*
FROM messages
INNER JOIN users
ON users.id = messages.sender_id
AND users.id = messages.rec_id
but it seems not working as i want .. so any idea
update i ment by it deosn't seems to be working, that it gives the sender and reciver name are the same which is wrong !!
msg_id | sender | reciver | text
------------------------------------
1 | david | david | hello friend
2 | eva | eva | pick me up
You probably want to join multiple times
SELECT users1.*, users2.*,messages.*
FROM messages
INNER JOIN users1
ON users1.id = messages.sender_id
INNER JOIN users2
AND users2.id = messages.rec_id
You need two joins:
SELECT m.*, us.username as sender_name, ur.username as receiver_nae
FROM messages m JOIN
users us
ON us.id = m.sender_id JOIN
users ur
ON ur.id = m.rec_id;
In your current condition, the user id is equal to both the sender and the receiver id, meaning you will only query messages someone sent himself - which is probably not what you want to achieve. Instead, you can join on users twice, once for the sender and once for the receiver:
SELECT m.msg_id, s.username AS sender, r.username AS receiver, m.text
FROM messages m
JOIN users s ON m.sender_id = s.id
JOIN users r ON m.rec_id = r.id

Join users table with last conversation query

I need to join user info table with chat messages query for last reply.
Chat table
mid | sender | receiver| text | created
1 | chrys | Paul| Hello | 2015-12-08 20:00
2 | chrys2 | Chrys | Hey | 2015-12-08 20:10
For the last reply result i am using that script:
mysql_query("
select *
from
chat
join
(select user, max(created) m , COUNT(*) AS msgCount
from
(
(select mid, receiver user, created
from chat
where sender='$login_session' )
union
(select mid, sender user, created
from chat
where receiver='$login_session')
) t1
group by user) t2
on ((sender='$login_session' and receiver=user) or
(sender=user and receiver='$login_session')) and
(created = m)
order by created desc
");
My problem is that i can't figure out how to join a user info table like the following:
id | username | photo_url | age | etcetera.....
Some ideas?
All i need is to get infos about users wich are sendind messages like photo, age from the users_info table.
As per your query, you are trying to get last chat message sent or received for the logged in user.
For that,
select c.*
from chat c
join users u on u.id = c.receiver_id or u.id = c.sender_id
where u.id = 'SESSION.User.Id'
order by c.id desc
Meanwhile i found the answer. Here it is:
select c.*, u.photo
from chat c
join users u on u.username = c.sender
WHERE (sender = '$login_session' AND receiver = '$uid') OR
(sender = '$uid' AND receiver = '$login_session')

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

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