2012-06-09 25 views
1

我已经为用户创建了一个消息系统,允许用户将消息发送给另一个消息。在mysql中以特定格式显示消息php

为此我创建了两个表格。

conversation(conversation_id,user_id1,user_id2) 
    messages(message_id,conversation_id,sender_id,receiver_id,message,created_time) 

如果用户正在谈论第一次,一个conversation_id将与user_id1(谁发起聊天)和user_id2创建(以谁user_id1在发送消息)

信息表将包含有关消息的所有信息。

现在我想要创建一个消息摘要页面,其中登录用户可以查看他的所有会话列表,其他用户按照created_time排序,按conversation_id排序。

下面是表中的数据:

conversation_id | user_id1 | user_id2 
    1    100  103 
    2    101  103 
    3    103  102   


message_id| conversation_id| sender_id| receiver_id| message | created_time 
    1    1   100  103   MSG A 2012-06-08 08:38:57 
    2    1   103  100   MSG B 2012-06-08 08:39:40 
    3    2   101  103   MSG C 2012-06-08 08:40:20 
    4    3   102  103   MSG D 2012-06-08 08:41:10 

而且这里是输出什么,我在寻找:让我们的用户说已登录的ID为:103

conversation_id| conversation_with | last_message | created_time 
     3    102    MSG D   2012-06-08 08:41:10 
     2    101    MSG C   2012-06-08 08:40:20 
     1    100    MSG B   2012-06-08 08:39:40 

所以这个输出是按created_time排序,按conversation_id分组,并在conversation_with中显示用户的id,以及谁正在进行对话。

有人可以提供MySQL查询我需要得到这个输出。

回答

1

这是一个有趣的。所以,你需要解决三个主要问题。

  1. 替代conversation_with列取决于所需用户在两列之间出现的位置。
  2. greatest-n-per-group找到最近的message
  3. least-n-per-group找到最早的消息created_time

我通过查询两次,交替user_id柱,unioning的结果,然后通过created_time订购联合在一起的结果要解决的第一个。我想我可以用一个查询来解决这个问题,而且没有联盟,但是现在它可以工作。

2和3有一点涉及。下面是与查询SQL小提琴:http://sqlfiddle.com/#!2/bf2b7/1

TL; DNR

select * from (
    select c.conversation_id, c.user_id2 as conversation_with, m1.message as last_message, m3.created_time 
    from conversation as c 
     join messages as m1 on c.conversation_id = m1.conversation_id 
     left outer join messages as m2 on (c.conversation_id = m2.conversation_id 
             and (m1.created_time < m2.created_time OR m1.created_time = m2.created_time AND m1.message_id < m2.message_id)) 
     join messages as m3 on c.conversation_id = m3.conversation_id 
     left outer join messages as m4 on (c.conversation_id = m4.conversation_id 
             and (m3.created_time > m4.created_time OR m3.created_time = m4.created_time AND m3.message_id > m4.message_id)) 
    where user_id1 = 103 and m2.message_id is null and m4.message_id is null 
    union all 
    select c.conversation_id, c.user_id1 as conversation_with, m1.message as last_message, m3.created_time 
    from conversation as c 
     join messages as m1 on c.conversation_id = m1.conversation_id 
     left outer join messages as m2 on (c.conversation_id = m2.conversation_id 
             and (m1.created_time < m2.created_time OR m1.created_time = m2.created_time AND m1.message_id < m2.message_id)) 
     join messages as m3 on c.conversation_id = m3.conversation_id 
     left outer join messages as m4 on (c.conversation_id = m4.conversation_id 
             and (m3.created_time > m4.created_time OR m3.created_time = m4.created_time AND m3.message_id > m4.message_id)) 
    where user_id2 = 103 and m2.message_id is null and m4.message_id is null 
             ) as conversations 
order by created_time desc 
+0

太好了!你已经做到了!如果我们考虑速度和性能呢? – Jadzia

+0

大量的性能测试需要完成,但通常“最大/最小每组数”非常有效。你需要在'created_time'上添加和索引,如果你在消息和会话之间创建了一个外键,那么这些外键也会被索引。 – HackedByChinese

+0

我将SQL小提琴更新为带有一些主键,索引和外键的版本。 – HackedByChinese