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

Mysql:从联接表中获取最后一行,mysql,subquery,Mysql,Subquery,我知道这个问题已经被问过很多次了,但我在实施上遇到了困难。MySQL并不是我最大的优势 我已经为我的网站建立了一个电子邮件系统,我想做的是当用户查看他们的收件箱时,他们会看到他们的邮件,但是他们会看到该特定邮件的最新发件人、日期和用户详细信息,而不是原始发件人、日期和用户详细信息 我的表格结构如下: 消息头: ----------------------- messageid INT type VARCHAR subject VARCHAR ----------

我知道这个问题已经被问过很多次了,但我在实施上遇到了困难。MySQL并不是我最大的优势

我已经为我的网站建立了一个电子邮件系统,我想做的是当用户查看他们的收件箱时,他们会看到他们的邮件,但是他们会看到该特定邮件的最新发件人、日期和用户详细信息,而不是原始发件人、日期和用户详细信息

我的表格结构如下:

消息头

-----------------------
messageid    INT
type         VARCHAR
subject      VARCHAR
-----------------------
id           INT
messageid    INT
userid       INT
isread       ENUM
isspam       ENUM
isdelete     ENUM
--------------------
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
邮件收件人

-----------------------
messageid    INT
type         VARCHAR
subject      VARCHAR
-----------------------
id           INT
messageid    INT
userid       INT
isread       ENUM
isspam       ENUM
isdelete     ENUM
--------------------
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
消息详细信息

-----------------------
messageid    INT
type         VARCHAR
subject      VARCHAR
-----------------------
id           INT
messageid    INT
userid       INT
isread       ENUM
isspam       ENUM
isdelete     ENUM
--------------------
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'

如果有人能给我指点,或是有人对此进行优化,我将不胜感激。如果你需要更多的信息,请告诉我

这可能有一个例外。。。以色列国旗

首先,我从一个“预查询”开始,它基于单个消息(加入到细节表)、消息中的最新序列(通过max(mr.id)),以及为给定用户创建的最新细节条目(假设通过max(md.DtlID)自动递增细节),这些记录不是垃圾邮件,也没有被删除。因此,每个消息ID最多只能提供一条记录

也就是说,我们现在可以直接连接回消息ID 1:1 join上的头

然后,按最近收到的序列1:1连接回邮件收件人。。。如果一封连锁邮件来回发送了10多次,那么我认为您应该希望收到与邮件ID相关的最新电子邮件。因此,这是我们获得“IsRead”标志的记录。。。即使有人能读到最近的一封邮件,但从未读过电子邮件链中的前一封

接下来,1:1连接到消息详细信息表(通过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

哇,太谢谢你了。我真的很感激你为回答这个问题所付出的努力。isread标志实际上只会随着messages\u detail表的每次添加而更新,并且message\u收件人与用户之间有1-1关系。我已经修改了查询以反映这一点,您是否认为它保持在您所做的优化范围内@PaulM,我不这么认为。。。一个消息ID似乎有多个可能的条目,因此它也有一个ID字段,指示它的唯一ID。如果在message_recipient表中有多个条目指向同一用户的相同消息ID,那么我认为您的版本将无法像我的版本那样有效地适应。。。但如果没有看到实际数据,我也可能是错的。我只想确保message_recipient表在(userid、isspam、isdelete)上有一个索引,以进一步优化查询……太棒了,非常感谢您的帮助。我已经让查询完全按照我的要求运行。