2015-03-08 61 views
0

我有三张桌子,我需要所有人的不同数据。可悲的是我也需要能够提取最新的行。这可能在一个快速的MySQL查询?

这里是我的表:

消息:我只是存储在表的内部邮件的内容,因为一个文本可以被发送给多个用户

+------------+------------------+------+-----+---------+----------------+ 
| Field  | Type    | Null | Key | Default | Extra   | 
+------------+------------------+------+-----+---------+----------------+ 
| message_id | int(10) unsigned | NO | PRI | NULL | auto_increment | 
| content | varchar(255)  | NO |  | 0  |    | 
+------------+------------------+------+-----+---------+----------------+ 

对话:这表格仅反映两个用户之间的单个对话。

+-----------------+------------------+------+-----+---------+----------------+ 
| Field   | Type    | Null | Key | Default | Extra   | 
+-----------------+------------------+------+-----+---------+----------------+ 
| partner_id  | int(10) unsigned | NO | MUL | NULL |    | 
| conversation_id | int(10) unsigned | NO | PRI | NULL | auto_increment | 
| expedition_id | int(11)   | NO |  | NULL |    | 
| active   | tinyint(4)  | NO |  | 1  |    | 
+-----------------+------------------+------+-----+---------+----------------+ 

conversation_messages:此表存储的实际消息中的信息交换。

+-----------------+------------------+------+-----+---------+-------+ 
| Field   | Type    | Null | Key | Default | Extra | 
+-----------------+------------------+------+-----+---------+-------+ 
| message_id  | int(11) unsigned | NO | PRI | NULL |  | 
| receiver_id  | int(11) unsigned | NO | PRI | NULL |  | 
| conversation_id | int(11) unsigned | NO | MUL | NULL |  | 
| status   | tinyint(4)  | NO |  | NULL |  | 
| timestamp  | datetime   | YES |  | NULL |  | 
+-----------------+------------------+------+-----+---------+-------+ 

我想现在要做的是选择每个会话中的最新消息,并从此消息中获取内容。 (这听起来很简单,但它没有找到一个简单的解决方案)。我试过如下:

SELECT max(c_m.message_id), m.content, c_m.`status` 
FROM expedition_conversations e_c, conversation_messages c_m 
    INNER JOIN messages m ON m.message_id = c_m.message_id 
WHERE e_c.expedition_id = 1 AND (c_m.conversation_id = e_c.conversation_id)  
GROUP BY c_m.conversation_id; 

可悲的是,因为GROUP BY内部似乎选择了第一个插排的大部分时间中,content我选择从messages表是错误的,而从conversation_messages选择message_id是正确的。

任何想法如何在一个查询中执行此操作?如果你有任何改变表格结构的建议,我也会很感激。

在此先感谢。

+0

您使用的是哪个版本的mysql? – Bohemian 2015-03-08 21:34:25

+0

版本5.6.19。 – puelo 2015-03-08 21:36:33

回答

1

你可能想试试这个版本:

SELECT c_m.message_id, m.content, c_m.`status` 
FROM expedition_conversations e_c join 
    conversation_messages c_m 
    ON c_m.conversation_id = e_c.conversation_id INNER JOIN 
    messages m 
    ON m.message_id = c_m.message_id 
WHERE e_c.expedition_id = 1 AND 
     NOT EXISTS (SELECT 1 
        FROM conversation_messages cm2 
        WHERE cm2.conversation_id = c_m.conversation_id AND 
         cm2.timestamp > c_m.timestamp 
       ) 

出于性能考虑,你想对conversation_messages(conversation_id, timestamp)的索引。

+0

谢谢你这样做的工作就像一个魅力! – puelo 2015-03-08 21:44:17

1

这是可能的,因为你的AUTO_INCREMENT手段的使用,即最高ID属于最新消息:

SELECT 
    messages.*, 
FROM 
    conversations 
    INNER JOIN (
    SELECT conversation_id, MAX(message_id) AS maxmsgid 
    FROM conversation_messages 
    GROUP BY conversation_id 
) AS latest ON latest.conversation_id=conversations.id 
    INNER JOIN messages 
    ON messages.message_id=latest.maxmsgid 
WHERE 
    1=1 -- whatever you want or need! 

由于此查询注定是相当缓慢的,你可能要考虑几个选择:它

  • 投掷硬件:使用足够的内存,并配置MySQL来晚去到磁盘的临时经理表作为possibel
  • 使用非规范化,并有ON AFTER INSERT触发Ø ñmessages更新上conversation_messages场,保持最新的消息ID
+0

谢谢。我会记住你的两个选择。 Upvoted你,而不是接受作为答案,因为我确实使用上面的解决方案;) – puelo 2015-03-08 21:44:50

0

试试这个小窍门:

SELECT c_m.message_id, m.content, c_m.status 
FROM expedition_conversations e_c 
JOIN (select * from (
    select * from conversation_messages 
    order by message_id desc) x 
    group by conversation_id) c_m ON c_m.conversation_id = e_c.conversation_id 
INNER JOIN messages m ON m.message_id = c_m.message_id 
WHERE e_c.expedition_id = 1 

这会在你的工作版本,如果MySQL - 5.6.19 - 并且应该在性能等方法。