我有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。
答案 0 :(得分:1)
您可以将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
答案 1 :(得分:1)
假设更高的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
答案 2 :(得分:1)
以下按要求运作:
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发送的最新消息,而不是必须匹配to / from元组,因为这会给查询增加无用的混乱。要得到这个,我会使用:
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
,理论是因为你的元组(UserID, ToUserID)
中有2个成员,所以在任何组合中,最大和最小的将是同样的,例如:
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中,最大和最小的将是相同的,因此您可以使用它将表连接到自身。
答案 3 :(得分:1)
您的查询有两部分 以下顺序:
因此,让我们获取UserID a和UserID b之间对话的最新消息:
SELECT *
FROM message
WHERE (toUserID, userID) IN ((a, b), (b, a))
ORDER BY message.time DESC
LIMIT 1
然后,您希望将这些组合用于UserID 1和2以及UserID 1和4之间的两个对话。这是联盟发挥作用的地方(我们不需要检查重复项,因此我们使用UNION ALL,谢谢马库斯亚当斯,他首先提出了这个问题。)
所以完整而直接的解决方案将是:
(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。