【问题标题】:Private chat system - get last message of each chat私人聊天系统 - 获取每个聊天的最后一条消息
【发布时间】:2018-10-09 16:44:37
【问题描述】:

我正在创建 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,您始终可以在顶部看到任何聊天的第一条消息。

问题是,如果用户是发件人,我只能得到最后一条消息,如果他是接收者,则不能:

 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 将具有相同的 chat_id,无论他们是发送者还是接收者,并且在这个例子中,用户 13 和 44 会有不同),

或者,有更好的选择吗?

【问题讨论】:

  • 基于示例数据的预期输出是什么?

标签: mysql sql


【解决方案1】:

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

  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 

【讨论】:

  • 我假设聊天表会变得非常大,我建议 @pileup 为这个查询创建这些索引 KEY(message_id, sender_id)KEY(message_id, receiver_id)
  • Raymond 我对 SQL 很陌生,你能解释一下这两个键是什么意思吗?您的意思是 2 个单独的表?
  • 不,KEY 是加快选择速度的表索引(dev.mysql.com/doc/refman/8.0/en/mysql-indexes.html)。 @pileup 阅读 dev.mysql.com/doc/refman/8.0/en/create-index.html
  • 谢谢雷蒙德! @scaisEdge - 我编辑了示例和小提琴以包含用户 20 参与的另外 1 行:与另一个用户“57”聊天,所以我应该得到 2 行。但是在您的查询中,我只得到“sender_id”发送的最后一条消息的 1 行,如果他收到一条消息,那么它就会消失
【解决方案2】:

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

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)
                      );

【讨论】:

  • 这几乎可以工作了,问题是我只收到任何聊天的最后一条消息。如果您在上面的示例中看到我添加了另一行,那么对于 'sender_id' 20 我应该得到 2 行:第 2 行和第 4 行(与用户 100 聊天并与用户 57 聊天)。但是我得到了用户 20 发送或接收的最后一条消息,而不是得到每个不同聊天的最后一条消息
猜你喜欢
  • 2015-05-30
  • 1970-01-01
  • 1970-01-01
  • 2022-10-26
  • 2021-02-07
  • 1970-01-01
  • 2020-01-16
  • 2013-02-02
  • 2016-09-09
相关资源
最近更新 更多