![](/img/trans.png)
[英]How do I select only the most recent record based on a userid that can be in either of two columns?
[英]Select most recent record based on two conditions
我有user1与user2和user4交换消息(这些参数是已知的)。 我现在想为每个对话选择最新发送或接收的消息(即每个对话的LIMIT 1)。
目前,我的查询返回所有会话的所有消息:
SELECT *
FROM message
WHERE (toUserID IN (2,4) AND userID = 1)
OR (userID IN (2,4) AND toUserID = 1)
ORDER BY message.time DESC
返回的行应该是messageID 3和6。
你可以通过ORDER BY
和LIMIT
将它分成两个查询然后用UNION
加入它们来轻松完成:
(SELECT *
FROM message
WHERE (toUserID IN (2,4) AND userID = 1)
ORDER BY message.time DESC
LIMIT 1)
UNION
(SELECT *
FROM message
WHERE (userID IN (2,4) AND toUserID = 1)
ORDER BY message.time DESC
LIMIT 1)
括号在这里很重要,这会返回消息2和6,这看起来是正确的,而不是3和6。
看起来你可以使用UNION ALL
来代替UNION
因为两个查询之间不会有重复,但如果你决定这样做会更好。
这是你的数据:
MESSAGEID USERID TOUSERID MESSAGE TIME
1 1 2 nachricht 1 123
2 1 2 nachricht 2 124
3 2 1 nachricht 3 125
4 3 2 nachricht wrong 1263
5 2 4 nachricht wrong 1261
6 4 1 nachricht sandra 126
假设更高的id
值表示更新的消息,您可以这样做:
SELECT *
FROM message
WHERE messageID IN (
SELECT MAX(messageID)
FROM message
WHERE userID = 1 -- optionally filter by the other user
OR toUserID = 1 -- optionally filter by the other user
GROUP BY CASE WHEN userID = 1 THEN toUserID ELSE userID END
)
ORDER BY messageID DESC
以下按要求工作:
SELECT m1.*
FROM Message m1
LEFT JOIN Message m2
ON LEAST(m1.toUserID, m1.userID) = LEAST(m2.toUserID, m2.userID)
AND GREATEST(m1.toUserID, m1.userID) = GREATEST(m2.toUserID, m2.userID)
AND m2.time > m1.Time
WHERE m2.MessageID IS NULL
AND ( (m1.toUserID IN (2,4) AND m1.userID = 1)
OR (m1.userID IN (2,4) AND m1.toUserID = 1)
);
为了简化其工作原理,假设您只需要用户ID 1发送的最新消息,而不是必须匹配来自/来自元组,因为这会使查询无效并增加混乱。 要得到这个我会使用:
SELECT m1.*
FROM Message AS m1
LEFT JOIN Message AS m2
ON m2.UserID = m1.UserID
AND m2.time > m1.time
WHERE m1.UserID = 1
AND m2.MessageID IS NULL;
因此,我们正在加入类似的消息,规定第二条消息(m2)的时间比第一条消息的时间长,其中m2为空,这意味着后期没有类似的消息,因此m2是最新的消息。
确切地说,主体已应用于解决方案中,但我们有一个更复杂的连接来链接对话。
我在连接中使用了LEAST
和GREATEST
,理论是因为你的元组中有2个成员(UserID, ToUserID)
,所以在任何组合中,最大和最小的将是相同的,例如:
From/To | Greatest | Least |
--------+-----------+-------+
1, 2 | 2 | 1 |
2, 1 | 2 | 1 |
1, 4 | 4 | 1 |
4, 1 | 4 | 1 |
4, 2 | 4 | 2 |
2, 4 | 4 | 2 |
正如您所看到的,在类似的From / To中,最大和最小的将是相同的,因此您可以使用它将表连接到自身。
查询分为两部分 , 顺序如下 :
因此,让我们获取UserID a和UserID b之间对话的最新消息:
SELECT *
FROM message
WHERE (toUserID, userID) IN ((a, b), (b, a))
ORDER BY message.time DESC
LIMIT 1
然后你想要将这些组合用于UserIDs 1和2以及UserIDs 1和4之间的两个对话。这是联盟发挥作用的地方(我们不需要检查重复项,因此我们使用UNION ALL,感谢Marcus Adams谁首先提出了这个问题。
因此,一个完整而直接的解决方案是:
(SELECT *
FROM message
WHERE (toUserID, userID) IN ((2, 1), (1, 2))
ORDER BY message.time DESC
LIMIT 1)
UNION ALL
(SELECT *
FROM message
WHERE (toUserID, userID) IN ((4, 1), (1, 4))
ORDER BY message.time DESC
LIMIT 1)
正如预期的那样,您在SQLFiddle中收到消息3和6。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.