0

所以我有一个如下所示的 SQL 表。这张桌子是一堆人与人之间的短信。我想获取所有存在的线程。这基本上意味着两个人之间的最后一条消息。我该怎么做呢?

-------------------------------------------------------
| sender_id  |  receiver_id  | message   | time         |
-------------------------------------------------------
| 123        |  456          | hi        | 4/17/2013    | 
--------------------------------------------------------
| 123        |  111          | hi        | 4/18/2013    | 
--------------------------------------------------------
| 123        |  555          | hi        | 4/19/2013    | 
-------------------------------------------------------- 
| 555        |  123          | hi        | 4/20/2013    | 
--------------------------------------------------------
| 444        |  333          | hi        | 4/21/2013    | 
--------------------------------------------------------
| 123        |  555          | hi        | 4/22/2013    | 
--------------------------------------------------------
| 777        |  123          | hi        | 4/23/2013    | 
--------------------------------------------------------

我想得到如下user= 123的响应行。请注意 sender_id 和 receiver_id 作为一个整体是如何唯一的。这意味着 joe 发送给 bob 的消息与 bob 发送给 joe 的消息在同一个线程中。

-------------------------------------------------------
| sender_id  |  receiver_id  | message   | time         |
-------------------------------------------------------
| 123        |  456          | hi        | 4/17/2013    | 
--------------------------------------------------------
| 123        |  111          | hi        | 4/18/2013    | 
--------------------------------------------------------
| 123        |  555          | hi        | 4/22/2013    | 
--------------------------------------------------------
| 777        |  123          | hi        | 4/23/2013    | 
--------------------------------------------------------
4

5 回答 5

4

一个更易于阅读的版本,它正确处理日期排序(如问题所示)并利用索引:

SELECT sender_id, receiver_id, message, time FROM
(
SELECT sender_id, receiver_id, message, time
FROM myTable 
WHERE sender_id = 123 OR receiver_id = 123
ORDER BY time DESC
) a
GROUP BY (CASE WHEN sender_id = 123 THEN receiver_id
   ELSE sender_id END);

SQL小提琴

于 2013-06-13T20:54:37.463 回答
0

用户 123 只是示例,我认为这里需要更一般的查询。此解决方案避免了耗时的连接,仅假设最多 10000 个用户(易于扩展)

SELECT sender_id, receiver_id, message, MAX(time), 
IF(sender_id<receiver_id, sender_id*10000+receiver_id, receiver_id*10000+sender_id) as thread_id 
FROM messages
GROUP BY thread_id
ORDER BY MAX(time) DESC

http://sqlfiddle.com/#!2/c65d3/30

更新:此版本不受用户数量限制:

SELECT sender_id, receiver_id, message, MAX(time), 
IF(sender_id<receiver_id, CONCAT(sender_id,receiver_id), CONCAT(receiver_id,sender_id)) as thread_id 
FROM messages
GROUP BY thread_id
ORDER BY MAX(time) DESC

http://sqlfiddle.com/#!2/c65d3/31

于 2013-06-13T22:37:10.570 回答
0

这应该适合你:

SELECT sender_id, receiver_id, message, time FROM your_table GROUP BY sender_id, receiver_id ORDER BY time DESC;
于 2013-06-13T20:32:33.820 回答
0

还没有实际测试过,但以下查询应该为每个不同/组合(在两个“方向”)返回最新的1条消息:sender_idreceiver_id

SELECT *
FROM message m1
WHERE time = (
    SELECT MAX(time)
    FROM message m2
    WHERE
        (m1.sender_id = m2.sender_id AND m1.receiver_id = m2.receiver_id)
        OR (m1.sender_id = m2.receiver_id AND m1.receiver_id = m2.sender_id)
)        

简而言之:选择每条消息,使其在同一发送者/接收者或接收者/发送者的所有消息中具有最大时间。

如果需要,您可以通过修改外部 WHERE 子句轻松地将其限制为给定用户,例如:

--- || ---
AND (sender_id = 123 OR receiver_id = 123)

1time请注意,如果不是唯一的,则可能有多个“最新”消息。

于 2013-06-13T21:06:14.627 回答
0

这应该这样做:

SELECT * FROM (
  SELECT sender_id, receiver_id, 
    IF(sender_id > receiver_id, CONCAT(sender_id, '_', receiver_id), 
   CONCAT(receiver_id, '_', sender_id)
    ) AS conversation_key, 
    message, `time` 
FROM sms_messages WHERE sender_id = 123
UNION ALL
SELECT sender_id, receiver_id, 
    IF(
      sender_id > receiver_id, 
      CONCAT(sender_id, '_', receiver_id), 
  CONCAT(receiver_id, '_', sender_id)
    ) AS conversation_key, message, `time` 
FROM sms_messages WHERE receiver_id = 123
) t 
GROUP BY conversation_key ORDER BY NULL
于 2013-06-13T20:49:42.543 回答