Mysql:从连接表中获取最后一行

时间:2011-06-16 19:16:41

标签: mysql subquery

我知道这个问题已被多次询问,但我在实施它时遇到了麻烦。 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'

但显然它将整体查询限制为仅一行!

我已经广泛地浏览了一下,我把它拼凑在一起,但是我担心它没有被优化并且会成为一头猪:

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'

我会很感激任何指针或有人优化这一点。如果您需要更多信息,请告诉我们!

1 个答案:

答案 0 :(得分:0)

这可能有一个例外...... IsRead标志。

首先,我开始使用“PreQuery”来获取基于单个Message(加入详细信息表),消息中最新的Sequence(通过max(mr.id))和最新的DETAIL创建的条目(假设通过Max(md.DtlID)自动递增详细信息)仅针对给定用户的那些非垃圾邮件且未删除的记录。因此,这给了我们MOST,每个消息ID一条记录。

话虽这么说,我们现在可以直接连接到消息ID 1:1加入的标题

然后,1:1加入返回收到的最新序列的消息接收者...如果链消息来回10次以上,这里是我假设你想要最近的电子邮件RECEIVED关联使用消息ID。所以,这是我们获得“IsRead”标志的记录......即使有人可以阅读更新的,但从未在电子邮件链中读过先前的内容。

接下来,1:1加入MESSAGE DETAIL表(通过Max(md.DtlID))获取给定消息的最后一条消息详细信息。我们不必加入消息ID,因为我们直接拥有消息的详细ID ...

最后,我们的详细信息可以加入users表以获取“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