开发者

MySQL GROUP BY / ORDER BY issue with flat messages table / threads

开发者 https://www.devze.com 2023-03-15 01:27 出处:网络
Ok, I\'m trying to base something similar off of this, but not quite getting it nailed: GROUP BY and ORDER BY

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.

0

精彩评论

暂无评论...
验证码 换一张
取 消

关注公众号