私人聊天系统 - 获取每个聊天的最后一条消息

时间:2018-04-29 11:31:23

标签: mysql sql

我正在2个用户之间建立聊天系统。 我有一个看起来像这样的聊天表:(这是架构:SQL Fiddle

        --------------------------------------------------------------------------------
        | message_id | sender_id | receiver_id  | message_text  |       date           |
        --------------------------------------------------------------------------------
        |     1      |     20    |      100     |  Hello mate   |  2018-04-29 12:15:33 | 
        --------------------------------------------------------------------------------
        |     2      |    100    |      20      |   Hi there    |  2018-04-29 13:20:05 | 
        --------------------------------------------------------------------------------
        |     3      |     13    |      44      |   Alright     |  2018-04-29 14:35:15 | 
        --------------------------------------------------------------------------------
        |     4      |     20    |      57      |   Hi user 57  |  2018-04-29 16:44:34 | 
        --------------------------------------------------------------------------------

我想从用户参与的每个聊天中获取最后消息的行,因此在上面的示例中,用户20应该获得2行:message_id 2行(因为他正在与用户100进行聊天) ,虽然他没有发送最后一条消息),并且有一行message_id 4(因为他向用户57发送了消息) 它基本上就像WhatsApp,你总是在顶部有任何聊天的第一条消息。

问题是,如果用户是SENDER,我只能收到最后一条消息而不是他是接收者:

 SELECT * FROM chat 
 WHERE message_id IN 
(SELECT MAX(message_id) FROM chat WHERE sender_id=:sender_id 
 GROUP BY receiver_id) ORDER BY date DESC

我想我应该添加另一栏" chat_id"对于同一个聊天中的每2个用户来说,这是一个相同的数字(因此,无论用户100和20是发送者还是接收者,用户100和20将具有相同的chat_id,并且用户13和44在此示例中将具有不同),

或者,有更好的选择吗?

2 个答案:

答案 0 :(得分:0)

你可以使用发送者和接收者之间的联合来获得两者的结果

  You could use 
  select * 
  from chat 
  inner join  (
    select max(message_id) max_id, user from (
    select message_id, sender_id as  user
    from chat
    union 
    select message_id, receiver_id 
    from chat) t 
    ) t1 on t1.max_id = chat.message_id
          and chat.sender_id=:sender_id 

答案 1 :(得分:0)

要有效地处理这个问题,请从这两个查询开始:

select message_id, sender_id as other_id
from messages
where receiver_id = :user
order by message_id desc;

select message_id, receiver_id as other_id
from messages
where sender_id = :user
order by message_id desc;

这些可以使用两个索引进行优化:messages(receiver_id, sender_id, message_id)messages(sender_id, receiver_id, message_id)

您可以union all将它们放在一起并进行排序或聚合以获得最大值:

select m.*
from messages m
where m.message_id in (select max(message_id)
                       from ((select message_id, sender_id as other_id
                              from messages
                              where receiver_id = :user
                              order by message_id desc
                              limit 1
                             ) union all   
                             (select message_id, receiver_id as other_id
                              from messages
                              where sender_id = :user
                              order by message_id desc
                              limit 1
                             )
                            ) mm
                      );

子查询应该能够使用索引(实际上,"其他id"不需要)。然后,max()分为两行,in应该能够利用(message_id)上的索引。

编辑:

对于修订后的问题,我无法想出一个真正有效的方法。这是一种方法:

select m.*
from messages m
where m.message_id in (select max(m2.message_id)
                       from messages m2
                       where :user in (sender_id, receiver_id)
                       group by (case when sender_id = :user then receiver_id else sender_id end)
                      );