I know this question has been asked many times, but I am having trouble implementing it. MySQL isn’t my greatest strength here.
I’ve built an email system for my site and what I want to do is when a user views their inbox they see their messages, however they see the latest sender, date and user details for that particular message instead of the original sender, date and user details.
My table structure as follows:
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
I thought something like this would work:
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'
But apparently it limits the overall query to just 1 row!
I’ve looked around extensively and I’ve cobbled this together, but I’m worried its not optimised and will be a hog:
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'
I would appreciate any pointers or someone optimising this. if you need any more info please let me know!
This might help with one exception… the IsRead flag.
First, I’m starting with a “PreQuery” to get based on a single Message (joined to the detail table), the most recent Sequence within the message (via max( mr.id) ), AND the latest DETAIL entry created (assuming auto-incrementing details via Max( md.DtlID ) ) for only those records for the given user that are not spam and not deleted. So this gives us at MOST, one record per message ID.
That being said, we can now do a direct join back to the header on the message ID 1:1 join
Then, 1:1 join BACK TO the message recipient on the most recent sequence received… if a chain message is back and forth 10+ times, here is where I assumed you would have intended the most recent email RECEIVED associated WITH the message ID. So, THIS was the record we are getting the “IsRead” flag… even though someone could read a more recent, yet never read a prior in an email chain.
Next, 1:1 join to the MESSAGE DETAIL table (via Max( md.DtlID ) ) for the last message detail FOR the given message. We don’t have to join on the Message ID since we HAVE the DETAIL ID of the message directly…
Finally, our detail can then join to the users table to get the “From” user information.
Hope this helps, including the clarification on how to derive the result set…