2011-06-16 48 views
1

我知道這個問題已被詢問了很多次,但我在實施時遇到了問題。 MySQL在這裏並不是我最大的優勢。Mysql:從加入的表格中獲取最後一行

我爲我的網站構建了一個電子郵件系統,我想要做的是當用戶查看他們的收件箱他們看到他們的消息,但他們看到最新的發件人,日期和用戶的詳細信息,而不是原始發件人,日期和用戶詳細信息。

我的表結構如下:

Message_Header

----------------------- 
messageid INT 
type   VARCHAR 
subject  VARCHAR 

Message_Recipient

----------------------- 
id   INT 
messageid INT 
userid  INT 
isread  ENUM 
isspam  ENUM 
isdelete  ENUM 

Message_Detail

-------------------- 
dtlid  INT 
messageid INT 
from_userid INT 
hash   VARCHAR 
type   SMALLINT 
body   TEXT 
title  VARCHAR 
subtitle  VARCHAR 
content  TEXT 
thumb  VARCHAR 
url   TEXT 
images  VARCHAR 
time_sent DATETIME 
timestamp INT 

我覺得像這樣的工作:

select mh.messageid, mh.subject, mh.type, mr.isread, msg_dtl.from_userid, msg_dtl.firstname, msg_dtl.lastname, msg_dtl.gender, msg_dtl.avatar, msg_dtl.hash, msg_dtl.body, msg_dtl.time_sent 
from message_header mh 
inner join message_recipient mr on mr.messageid = mh.messageid 
inner join (
    select md.messageid, md.from_userid, u.firstname, u.lastname, u.gender, u.avatar, md.hash, md.body, md.time_sent 
    from message_detail md 
    inner join users u on u.userid = md.from_userid 
    order by md.time_sent desc 
    limit 1 
) as msg_dtl ON mh.messageid = msg_dtl.messageid 
where mr.userid = 5 
and mr.isspam = '0' 
and mr.isdelete = '0' 

但很顯然,它限制了整個查詢到只有1行!

我身邊看着廣泛和我鵝卵石這個在一起,但我很擔心它不是最優化的,將是一個豬:

SELECT msg_dtl.type, msg_dtl.subject, msg_dtl.isread, u.firstname, u.lastname, u.gender, u.avatar, md.body, md.timestamp 
FROM message_detail md 
INNER JOIN users u on u.userid = md.from_userid  
INNER JOIN 
(
    SELECT mr.userid, mh.type, mh.subject, mr.isspam, mr.isdelete, mr.isread, md.messageid, md.body, max(timestamp) as timestamp 
    FROM message_detail md 
    inner join message_header mh on mh.messageid = md.messageid 
    inner join message_recipient mr on mr.messageid = mh.messageid 
    GROUP BY md.messageid 
) as msg_dtl 
USING (timestamp, messageid) 
where msg_dtl.userid = 5 
and msg_dtl.isspam = '0' 
and msg_dtl.isdelete = '0' 

我將不勝感激優化這個任何指針或某人。如果您需要更多信息,請讓我知道!

回答

0

這可能有助於一個例外... IsRead標誌。首先,我將根據單個消息(加入到詳細信息表),消息中最近的序列(通過max(mr.id))獲取「PreQuery」,並以最新的僅針對給定用戶的非垃圾信息且未刪除的記錄,創建DETAIL條目(假定通過Max(md.DtlID)自動遞增詳細信息)。所以這給了我們在MOST,每個消息ID一個記錄。

話雖這麼說,我們現在能做的直接連接回的消息ID 1頭:1加入

然後,1:1上收到的最新的時序回郵件收件人加入.. 。如果一個鏈接消息來回10次以上,這裏是我假設你將會收到與消息ID相關聯的最新電子郵件RECEIVED。所以,這是我們獲得「IsRead」標誌的記錄......儘管有人可以閱讀更近的文章,但從來沒有在電子郵件鏈中讀過。

接下來,1:1連接到MESSAGE DETAIL表(通過Max(md.DtlID)),以獲得給定消息的最後一個消息詳細信息。我們不必加入消息ID,因爲我們直接具有消息的詳細ID ...

最後,我們的詳細信息可以加入到用戶表中以獲取「From」用戶信息。

希望這有助於,包括澄清如何派生結果集...

SELECT STRAIGHT_JOIN 
     PreQuery.MessageID, 
     mr2.IsRead, 
     mh.Type, 
     mh.Subject, 
     md.from_UserID, 
     md.isread, 
     md.body, 
     md.timestamp, 
     u.firstname, 
     u.lastname, 
     u.gender, 
     u.avatar 
    from 
     (SELECT 
       mr.MessageID, 
       MAX(mr.ID) as LastMessageSequence, 
       MAX(md.DtlID) as LastDetail 
      from 
       Message_Recipient mr 
       join Message_Detail md 
        ON mr.messageid = md.messageid 
      where 
        mr.userid = 5 
       and mr.isspam = '0' 
       and mr.isdelete = '0' 
      group by 
       mr.MessageID) PreQuery 

     JOIN Message_Recipient mr2 
     ON PreQuery.LastMessageSequence = mr2.ID 

     JOIN Message_Header mh 
     ON PreQuery.MessageID = mh.MessageID 

     JOIN Message_Detail md 
     ON PreQuery.LastDetail = md.DtlID 
     JOIN users u 
      on md.from_userid = u.userid 

    order by 
     md.timestamp desc 
+0

哇,非常感謝。我非常感謝你爲答案付出的努力。 isread標誌實際上只會隨着messages_detail表的每一個添加而更新,並且message_recipient與用戶具有1-1關係。我已經修改了查詢來反映這一點,你會說是保持在你已經完成的優化? http://pastebin.com/H1ZzYyEP – PaulM 2011-06-16 23:16:58

+0

@PaulM,我不這麼認爲......看起來一個消息ID有多個可能的條目,因此它有一個ID字段也表明了它的唯一ID。如果message_recipient表中的同一個用戶對同一個消息ID有多個條目,那麼我認爲你的版本不會像我的那樣有效地進行調整......但是我也可能錯誤地看不到實際的數據。我只想確保message_recipient表的索引(userid,isspam,isdelete)來優化查詢甚至更多... – DRapp 2011-06-16 23:34:53

+0

真棒,非常感謝您的幫助。我已經使查詢完全按照我的需要工作。 – PaulM 2011-06-17 10:57:28

相關問題