2015-03-08 65 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 - 並且應該在性能等方法。