如何根据可以位于两列中任意一列的用户 ID 仅选择最新记录?
我有一个 messages
表,其结构有点像这样:
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
我想在我的网站上显示一个与 Facebook 的消息页面非常相似的消息页面,该页面显示与用户进行对话的人员列表。无论对话的深度如何,该页面仅向每个人显示一次,以及与该特定人的对话中的最新消息,无论是发送还是接收。
让我困惑的是,最近的消息可以发送或接收,这意味着用户的 ID 号可以位于 from
或 to
列中。我不确定如何按照我需要的方式测试这两列。
我仍在学习如何编写更复杂的 MySQL 查询,虽然我觉得这是使用 OR
与子查询的简单情况,但我似乎无法正确理解。
解决方案 事实证明这根本不是一个非常简单的案例。 Widor 花了一些时间来帮助我解决这个问题,下面的查询似乎终于完成了这项工作。它尚未经过彻底测试,但到目前为止似乎工作正常:
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 messages
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
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 messages
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
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
重新编辑
我之前的答案(与这里的其他一些答案一样)没有考虑到您有超过 2 个对话“伙伴”的情况,这在您的示例数据中不是这种情况,但是我确信现实生活中也会如此。
因此,考虑一下数据中现在有一条额外记录的情况:
我修改后的查询如下:
因此,我们的内部
UNION
为我们提供了一个包含userid
以及partnerid
,即他们正在与谁聊天。如果您愿意,可以将其单独创建为视图,以简化查询。然后,外部
SELECT
会检索指定userid
与之聊天的每个“伙伴”的一条记录以及最近的日期。Max()
函数获取最新日期,GROUP BY
负责确保我们为每个合作伙伴返回多于一条记录。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:
My revised query is as follows:
So, our inner
UNION
gives us a dataset containing theuserid
along with apartnerid
, 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 specifieduserid
has had a chat with, along with the most recent date.The
Max()
function achieves the most recent date, and theGROUP BY
takes care of ensuring we bring back more then one record for each partner.听起来您想要类似的内容:
其中
id
是您用于用户 ID 的参数。Sounds like you want something like:
Where
id
is the parameter you're using for the user ID.您可以创建一个视图并查询它:
查看结果表,现在应该很容易查询您想要的内容
you can create a view and query it:
look at the result table, it should now be very easy to query what you want
我想你可能想要这样的东西:
你可以用实际值替换
$userid
,希望使用 准备好的声明。 :-)I think you probably want something like this:
You would replace
$userid
with the actual value, hopefully using prepared statements. :-)