Can't integrate INNER JOIN in my query - mysql

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.

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

Phpmyadmin not selecting correct vaues

I am running this query in my database:
SELECT * FROM posts INNER JOIN profile ON posts.user_id = profile.user_id
WHERE posts.user_id IN
(SELECT user_id FROM users WHERE class_name IN
(SELECT class_name FROM classroom WHERE created_by = '456'))
OR posts.user_id IN
(SELECT user_id FROM users WHERE role = 'teacher' AND school_name = 'SK Taman Megah')
ORDER BY posts.created_at DESC;
This is my classroom table:
This is my users table:
This is my post table:
This is my profile table:
This is my output:
Expected output should have a total of 4 rows with post_id of (60,57,61,56) but only 2 was shown. Is there a mistake in the SQL query?
I think following one is what you are expecting:
SELECT * FROM posts INNER JOIN profile ON posts.user_id = profile.user_id where posts.user_id IN (select distinct user_id from users left join classroom on classroom.class_name = users.class_name where classroom.created_by='456' or (users.role='teacher' and users.school_name='SK Taman Megah') )

how to select the last text from message table

I have two tables (messages and user). I want to select the last (msg_id,text) from the messages table for a particular ad_id and need to select the name of the user from the user table.
SELECT u.id
, m.date
, m.ad_id
, max(m.msg_id)as msg_id
, u.first_name
, m.text
, m.u_to_id
, m.u_from_id
FROM user u
JOIN messages m
ON CASE WHEN m.u_from_id ='14' THEN u.id = m.u_to_id
ELSE u.id = m.u_from_id END
AND (m.u_from_id='14' OR m.u_to_id='14')
AND m.ad_id='20'
GROUP BY CONCAT(m.ad_id,u.id)
ORDER by m.msg_id DESC
this query is working but I can't select t the last m.textTable structure
SELECT u.id, m.text
FROM user u
JOIN messages m ON m.msg_id = (SELECT max(msg_id) FROM messages WHERE u_from_id = u.id)
I simplified your query to show the logic relevant to your question. Basically you want to join your messages table on the msg_id that is equal to the inner query of the max msg_id with that user.
After so many experiments added a new column(bargainer) for identify the recipient and this query working fine for me
select m.msg_id,m.text,m.status,m.date,m.bargainer,m.ad_id,u.first_name,u.id from user u JOIN messages m where msg_id in (select max(msg_id) from messages m where m.ad_id=20 and u.id=m.bargainer group by(m.bargainer))group by(m.msg_id) order by msg_id DESC

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 - Get last message from all users

I've searched on stackoverflow already, but the existing threads did not help me, so im posting this.
My database schema:
user: user_id, displayname
message: id, sender_id, receiver_id, message, dateSent
What i want:
Show me a list of the latest message from each user WHERE receiver_id = 4
What i already tried:
MYSQL select newest posts from tables
query to get last message only from all users
Still can't solve my problem :(
Try this:
SELECT
u1.displayname AS SenderName,
m.date_sent,
...
FROM messages AS m1
INNER JOIN users AS u1 ON m1.sender_id = u1.id
(
SELECT sender_id, MAX(dateSent) MaxDate
FROM messages
GROUP BY sender_id
WHERE receiver_id = 4
) AS m2 ON m1.sender_id = m2.sender_id
AND m1.datesent = m2.maxdate
SELECT u.user_id, u.displayname, m.message
FROM user u
INNER JOIN
(SELECT id, sender_id, receiver_id, message, MAX(dateSent) AS mdate
FROM message msg
WHERE receiver_id = 4
GROUP BY sender_id
) as m
ON u.user_id = m.sender_id AND u.dateSent = m.mdate
HTH
SELECT m.id, MAX as mDate, m.sender_id, u.displayname
FROM message m
LEFT JOIN user u ON u.user_id = m.sender_id
WHERE m.receiver_id = 4
GROUP BY sender_id