Adding a extra subquery to MySQL query - mysql

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

Related

Can't integrate INNER JOIN in my query

Hello I'm using the query below to select the latest message from each unique conversation. Everything works perfectly except when I try to integrate an INNER JOIN to try to link the user's user_id with their username in the users table.
I've tried pretty much every combination to integrate the INNER JOIN so I decided to separate it from the working query until I get help.
I made a Fiddle http://sqlfiddle.com/#!9/a9bbc/1 I just want user_id on the right to print the user's username
SELECT message_id,
msg,
user_id
FROM messages
JOIN (SELECT user_id,
Max(dat) m
FROM ((SELECT message_id,
recipient_id user_id,
dat
FROM messages
WHERE owner_id = 1)
UNION
(SELECT message_id,
owner_id user_id,
dat
FROM messages
WHERE recipient_id = 1)) t1
GROUP BY user_id) t2
ON ( ( owner_id = 1
AND recipient_id = user_id )
OR ( owner_id = user_id
AND recipient_id = 1 ) )
AND ( dat = m )
ORDER BY dat DESC
.
users.username INNER JOIN users ON messages.user_id = users.user_id;
If messages.message_id is an AUTO_INCREMENT PRIMARY KEY column, this will probably be the fastest way to receive the desired result:
select m.message_id, m.msg, u.username,
case sub.other_user_id
when m.owner_id then 'received from'
when m.recipient_id then 'sent to'
end as direction
from (
select other_user_id, max(message_id) as message_id
from (
select recipient_id as other_user_id, max(message_id) as message_id
from messages
where owner_id = #uid
group by recipient_id
union all
select owner_id as other_user_id, max(message_id) as message_id
from messages
where recipient_id = #uid
group by owner_id
) sub
group by other_user_id
) sub
join messages m on m.message_id = sub.message_id
join users u on u.user_id = sub.other_user_id
order by sub.message_id desc
I've also added the column direction. This way you will know if the message has been sent or received. The result would be like:
| message_id | msg | username | direction |
|------------|------------------------------------------------------------------|----------|---------------|
| 9 | You should also see this | User3 | sent to |
| 8 | you should Now see this instead even with the owner_id flipped.. | User2 | received from |
http://sqlfiddle.com/#!9/a9bbc/34
Note that you can still add any column from the users and messages tables in the SELECT clause.
To get this query work fast you will need indexes on messages(owner_id, recipient_id) and messages(recipient_id, owner_id).
I think this is correct... finally. The not exists filters out responses after the start.. the inner query grabs the most recent conversation. This should match the expected output.
SELECT dT.maxid AS message_id
,(SELECT msg FROM messages M WHERE M.message_id = dT.maxid) AS message_id
,(SELECT username FROM users U WHERE U.user_id = dT.owner_id) AS user_id
FROM (
SELECT MAX(message_id) as maxid
,owner_id
,recipient_id
FROM messages M
GROUP BY owner_id, recipient_id
) AS dT
WHERE NOT EXISTS(SELECT *
FROM messages M2
WHERE M2.recipient_id = dT.owner_id
AND M2.owner_id = dT.recipient_id
AND M2.message_id > dT.maxid)
ORDER BY dT.maxid
Produces output:
message_id message_id user_id
8 you should Now see this instead even with the User2
owner_id flipped.. The users_id in the query is 1
and it gets the conversation with user_id 2
9 You should also see this User1
fiddle
When you have joined any tables or subqueries, you really really really need to include table name or table aliases with all column references. I changed the maximum dat to maxdat below so I could use m for messages.
SELECT
m.message_id
, m.msg
, m.user_id
FROM messages m
JOIN (
SELECT
user_id
, MAX(dat) maxdat
FROM (
(SELECT
message_id
, recipient_id user_id
, dat
FROM messages
WHERE owner_id = 1)
UNION
(SELECT
message_id
, owner_id user_id
, dat
FROM messages
WHERE recipient_id = 1)
) t1
GROUP BY
user_id
) t2 ON (
(m.owner_id = 1 AND m.recipient_id = t2.user_id)
OR (m.owner_id = t2.user_id AND m.recipient_id = 1)
)
AND (m.dat = t2.maxdat)
ORDER BY
m.dat DESC
You need to join your final result with users table and get the value of users.username based on user_id. Try this:
SELECT messages.message_id,
messages.msg,
users.user_id,
users.username
FROM users, messages
JOIN (SELECT user_id,
Max(dat) m
FROM ((SELECT message_id,
users.username,
recipient_id user_id,
dat
FROM messages
INNER JOIN users ON messages.recipient_id = users.user_id
WHERE owner_id = 1)
UNION
(SELECT message_id,
users.username,
owner_id user_id,
dat
FROM messages
INNER JOIN users ON messages.owner_id = users.user_id
WHERE recipient_id = 1)) t1
GROUP BY user_id) t2
ON ( ( owner_id = 1
AND recipient_id = user_id )
OR ( owner_id = user_id
AND recipient_id = 1 ) )
AND ( dat = m )
WHERE users.user_id = messages.user_id
ORDER BY dat DESC
If I understand correctly, you want the most recent messages where the send or recipient is "1" and associated user names.
That suggests:
select m.*, ur.username as recipient_name, us.username as sender_name
from messages m join
users ur
on m.recipient_id = ur.user_id join
users us
on m.sender_id = us.user_id
where m.date = (select max(m2.dat)
from messages m2
where 1 in (m2.recipient_id, m2.sender_id)
) and
1 in (m.recipient_id, m.sender_id);
EDIT:
Based on your SQL Fiddle the above understanding is not correct. You want to consider pairs of recipients, so I think you want:
select m.*, ur.username as recipient_name, us.username as sender_name
from messages m left join
users ur
on m.recipient_id = ur.user_id left join
users us
on m.owner_id = us.user_id
where m.dat = (select max(m2.dat)
from messages m2
where (m2.recipient_id, m2.owner_id) = (m.recipient_id, m.owner_id) or
(m2.recipient_id, m2.owner_id) = (m.owner_id, m.recipient_id)
) and
1 in (m.recipient_id, m.owner_id);
Here is the SQL Fiddle.
If the ordering of the pair is import (so (1, 2) is different from (2, 1) remove the second condition in the innermost where clause.

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')

search by date mysql

I have a table named messages:
date (format DATETIME)
id
text
user_id(FK)
and a table named users:
id
name
how to get count of messages with given date (message date = xxxx-xx-xx) for each user?
like:
user message_count
user1_name 5
user2_name 2
and how get users with 3 or more message today?
SELECT users.name
FROM users
WHERE Users.id IN ( SELECT Messages.user_id
FROM chat.Messages
GROUP BY Messages.user_id
HAVING COUNT(*) >=3
)
It returns users who have 3 or more messages, how to get users, who have 3 or more message today? where date = now()
How to get count of messages with given date (message date = xxxx-xx-xx) for each user?
Query #1:
SELECT
users.name,
COUNT(*) message_count
FROM messages
INNER JOIN users ON messages.user_id = users.id
WHERE messages.date = PUT_YOUR_DATE_HERE
GROUP BY messages.user_id;
How to get count of messages for those users who have 3 or more messages today?
Query #2:
SELECT
users.name,
COUNT(*) message_count
FROM messages
INNER JOIN users ON messages.user_id = users.id
WHERE messages.date = CURDATE()
GROUP BY messages.user_id
HAVING COUNT(*) >= 3;
select b.name,count(*) from messages a,users b where date ='2016-05-28' group by b.name

Query: How to obtain the most recent message per one user conversations?

I have a conversations table that is very simple but important (created_by is the code of the user who sent the message). Then, I have a conversations_messages table (sent_by is the code of the user who sent the message, message is my message text and created_at is the timestamp). Finally I have a conversations_users table that has the user_id (code of the user who received the message) and created_by (code of the user who sent the message).
I am trying to implement the functionality of inbox, I want to show the last message per conversation. user_id in conversations_users is the user who received the message and the user who is consulting his inbox.
I tried this query but I don't know how to deal with the created_at timestamp (in table conversations_messages) in order to get the most recent message per conversation.
select CM.id, CM.message, CM.created_at, C.id as 'conversation_id' from conversations_users CU
join conversations C on CU.conversation_id = C.id join conversations_messages CM on C.id = CM.conversation_id where CU.user_id = 1 and CM.created_at = '2015-03-10 14:18:02'
I have to replace '2015-03-10 14:18:02' for some most recent created_at timestamp thats my problem.
My tables are:
conversations_users: id, conversation_id, user_id, created_by
conversations: id, created_by
conversations_messages: id, conversation_id, sent_by, message, created_at
Thanks!
SELECT cm.*
FROM conversations_messages cm
JOIN conversations c ON cm.conversation_id = c.id
JOIN conversations_users cu ON cu.conversation_id = c.id
WHERE cu.user_id = 1
AND NOT EXISTS ( SELECT 'a'
FROM conversations_messages cm2
WHERE cm2.conversation_id = cm.conversation_id
AND cm2.created_at > cm.created_at
)
GROUP BY c.id
Here's one approach joining the table back to itself using the max aggregate, grouping by each conversation:
select CM.id, CM.message, CM.created_at, C.id as 'conversation_id'
from conversations_users CU
join conversations C on CU.conversation_id = C.id
join conversations_messages CM on C.id = CM.conversation_id
join (
select max(created_at) maxcreated_at, conversation_id
from conversations
group by conversation_id
) T on T.maxcreated_at = CM.created_at
and T.conversation_id = CM.conversation_id
where CU.user_id = 1

mySql Select last entry for each user

I have two tables:
users:
user_id user_name
data:
user_id user_data user_time
I wan to select the latest entry from the data table, but return the user_name, user_id, user_data and user_time.
I have tried the following query, but it returns the first entry, not the last for each user:
sql = "SELECT users.user_name, users.user_id, data.user_data, data.user_time
FROM users
INNER JOIN data ON data.user_id = users.user_id
GROUP BY users.user_name
ORDER BY data.user_time DESC";
Use GROUP BY and MAX, WHERE...IN:
SELECT u.user_id, u.user_name, d.user_data, d.user_time
FROM users u
INNER JOIN data d ON d.user_id = u.user_id
WHERE (d.user_id, d.user_time) =
(SELECT user_id, MAX(user_time) FROM data GROUP BY user_id)
I think you had better add data_id column to data table.
Unless data_id, both user_id and user_time are necessary for PRIMARY KEY(and user_time is not always unique, not reliable)
If there is data_id, it can be bitly simple:
SELECT u.user_id, u.user_name, d.user_data, d.user_time
FROM users u
INNER JOIN data d ON d.data_id =
(SELECT data_id FROM data
WHERE user_id = u.user_id ORDER BY data_time DESC LIMIT 1)