MySQL GROUP BY / ORDER BY issue with flat messages table / threads
Ok, I'm trying to base something similar off of this, but not quite getting it nailed: GROUP BY and ORDER BY
Basically, wanting a query to find the latest messages in each 'thread' between the current logged-in user and any other users, but via a flat (non-'threaded') table of messages:
messages {
id,
from_uid,
to_uid,
message_text,
time_added
}
Assuming the current user's uid is '1', and the latest message in each 'thread' could either be from that user, or to that user (the other party always denoted by thread_recipient):
SELECT a.*,thread_recipient
FROM messages a
JOIN (SELECT IF(from_uid = '1',to_uid,from_uid) AS thread_recipient,
MAX(time_added) AS recency
FROM messages
WHERE (from_uid = '1' OR to_uid = '1')
GROUP BY thread_recipient) b ON thread_recipient = (IF(a.from_uid = '1',a.to_uid,a.from_uid))
AND b.recency = a.time_added
ORDER 开发者_StackOverflow社区BY a.time_added DESC
But I fear this ain't gonna work right, and maybe messages sent at the same time might end up being returned for the wrong user?
Is my WHERE condition misplaced?
Any wisdom much appreciated.
Here's an idea: take the UNION of the following two queries, then get the maximum dates from the result.
SELECT id,to_uid AS other_party,time_added FROM messages WHERE from_uid = '1'
SELECT id,from_uid AS other_party,time_added FROM messages WHERE to_uid = '1'
When you do the following:
SELECT MAX(time_added),other_party
FROM (SELECT id,to_uid AS other_party,time_added FROM messages WHERE from_uid = '1'
UNION
SELECT id,from_uid AS other_party,time_added FROM messages WHERE to_uid = '1'
) MyMessages
GROUP BY other_party
You will get the most recent time associated with a message sent to each person that user '1' is corresponding with. Then you can join the results of that to the original messages table to get what you want:
SELECT Messages.*
FROM (SELECT MAX(time_added) AS MaxTime,other_party
FROM (SELECT id,to_uid AS other_party,time_added FROM messages WHERE from_uid = '1'
UNION
SELECT id,from_uid AS other_party,time_added FROM messages WHERE to_uid = '1'
) MyMessages
GROUP BY other_party
)
JOIN Messages
ON (Messages.time_added = MyMessages.MaxTime AND
(Messages.to_uid = MyMessages.other_party AND Messages.from_uid = '1' OR
Messages.from_uid = MyMessages.other_party AND Messages.to_uid = '1')
)
Try this - I think it gives you what you are looking for more simply and efficiently.
SELECT latest_time = MAX(a.time_added, b.time_added)
FROM messages a, messages b
LEFT JOIN messages a1
ON a1.from_uid = a.from_id
-- find the case where the following doesn't exist
-- so you know there is nothing after b1
LEFT JOIN messages a2
ON a2.from_uid = a.from_id
AND a2.time_added > a1.time_added
LEFT JOIN messages b1
ON b1.to_uid = b.to_id
LEFT JOIN messages b2
ON b2.to_uid = b.to_id
AND b2.time_added > b1.time_added
WHERE a.from_id = '1'
AND b.to_id = '1'
AND c1.id IS NULL
AND c2.id IS NULL
ORDER BY a.time_added DESC
Ok, after comments - if id is autoincrement use it instead of message time. But you have propoer condition to ensure that messages will not be delivered to wrong persons.
精彩评论