繁体   English   中英

根据两个条件选择最近的记录

[英]Select most recent record based on two conditions

我有user1与user2和user4交换消息(这些参数是已知的)。 我现在想为每个对话选择最新发送或接收的消息(即每个对话的LIMIT 1)。

SQLFiddle

目前,我的查询返回所有会话的所有消息:

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 BYLIMIT将它分成两个查询然后用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值表示更新的消息,您可以这样做:

  • 查找涉及用户1的所有消息
  • 按其他用户ID对结果进行分组
  • 获取每个组的最大消息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

更新了SQLFiddle

以下按要求工作:

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是最新的消息。

确切地说,主体已应用于解决方案中,但我们有一个更复杂的连接来链接对话。

我在连接中使用了LEASTGREATEST ,理论是因为你的元组中有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中,最大和最小的将是相同的,因此您可以使用它将表连接到自身。

查询分为两部分顺序如下

  1. 您希望最新的传出或传入消息用于两个用户之间的对话
  2. 您希望为两对不同的用户提供这些最新消息,即对话。

因此,让我们获取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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM