开发者

How do I select only the most recent record based on a userid that can be in either of two columns?

I have a messages table that is structured somewhat like this:

from  |  to  |  date
-----------------------------------
1     |  3   |  2011-09-23 11:51:44
3     |  1   |  2011-09-23 11:56:29
3     |  2   |  2011-10-04 10:20:01
2     |  3   |  2011-10-05 07:48:00

I want to display a messages page on my website very similar to Facebook's messages page, which shows a list of the people with which the user has a conversation. Regardless of the depth of the conversation, the page only shows each person once, along with the most recent message in that conversation with that particular person, whether it was sent or received.

The part that stumps me is that the most recent message can be either sent or received, which means that the user's ID number can be in either the from or to column. I'm not sure how to test against both columns the way I need to.

I'm still learning how to write more complex MySQL queries, and while I feel like this is a simple case of using OR with subqueries, I can't seem to get it right.

SOLUTION Turns out it wasn't really a very simple case at all. Widor took some time to help me out with this, and the following query finally seems to do the job. It hasn't been tested thoroughly, but so far it seems to work fine:

SELECT m.*
FROM   messages m
       JOIN (SELECT Max(x.id)      AS `id`,
                    x.userid,
                    x.partnerid,
                    Max(x.mostrecent) AS `mostrecent`
             FROM  (SELECT Max(id)     `id`,
                           `from`         AS `userid`,
                           `to`           AS `partnerid`,
                           Max(`created`) AS `mostrecent`
                    FROM   me开发者_StackOverflow社区ssages
                    GROUP  BY `from`,
                              `to`
                    UNION
                    SELECT Max(id)     `id`,
                           `to`           AS `userid`,
                           `from`         AS `partnerid`,
                           Max(`created`) AS `mostrecent`
                    FROM   messages
                    GROUP  BY `to`,
                              `from`) AS `x`
             GROUP  BY x.`userid`,
                       x.`partnerid`) AS `y`
         ON y.id = m.id
WHERE  y.userid = $userid


RE-EDITED

My previous answer (as some other ones here) didn't take account of the case where you have more than 2 conversation 'partners', which isn't the case in your example data but I'm sure will be in real life.

So consider the case where you now have an extra record in the data:

1    |     4    | 2011-10-04 08:34:12

My revised query is as follows:

SELECT userid, partnerid, max(mostRecent) from (
    SELECT [from] as [userid], [to] as [partnerid], max([date]) as [mostrecent] FROM messages GROUP BY [from], [to]
    UNION 
    SELECT [to] as [userid], [from] as [partnerid],max([date]) as [mostrecent] FROM messages GROUP BY [to], [from]
) [x]
WHERE userid = ?
GROUP BY userid, partnerid

So, our inner UNION gives us a dataset containing the userid along with a partnerid, i.e. who they are chatting to. This could be created separately as a view if you wanted, to simplify the query.

The outer SELECT then retrieves one record for every 'partner' that the specified userid has had a chat with, along with the most recent date.

The Max() function achieves the most recent date, and the GROUP BY takes care of ensuring we bring back more then one record for each partner.


Sounds like you want something like:

SELECT MAX(date), * FROM messages WHERE to IN (
    SELECT DISTINCT to FROM messages WHERE from = :id
) GROUP BY to
UNION
SELECT MAX(date), * FROM messages WHERE from IN (
    SELECT DISTINCT from FROM messages WHERE to = :id
) GROUP BY from
ORDER BY 1

Where id is the parameter you're using for the user ID.


you can create a view and query it:

CREATE VIEW dataview AS 
(SELECT t1.from AS userid, t1.date FROM messages AS t1) 
UNION
(SELECT t2.to AS userid, t2.date FROM messages AS t2)

look at the result table, it should now be very easy to query what you want


I think you probably want something like this:

SELECT MAX(date)
FROM messages
WHERE from = $userid
   OR to   = $userid

You would replace $userid with the actual value, hopefully using prepared statements. :-)

0

上一篇:

下一篇:

精彩评论

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

最新问答

问答排行榜