I have a query that gets all the info I need for a messaging system’s main page (including unread message count, etc)… but it currently retrieves the original threads message. I would like to augment the below query to grab the most recent message in each thread instead.
This query is very close, however my mediocre SQL skills are keeping me from wrapping things up…
$messages = array();
$unread_messages_total = 0;
$messages_query = "
SELECT m.*
, COUNT(r.id) AS num_replies
, MAX(r.datetime) AS reply_datetime
, (m.archived NOT LIKE '%,".$cms_user['id'].",%') AS message_archive
, (m.viewed LIKE '%,".$cms_user['id'].",%') AS message_viewed
, SUM(r.viewed NOT LIKE '%,".$cms_user['id'].",%') AS unread_replies
, CASE
WHEN MAX(r.datetime) >= m.datetime THEN MAX(r.datetime)
ELSE m.datetime
END AS last_datetime
FROM directus_messages AS m
LEFT JOIN directus_messages as r ON m.id = r.reply
WHERE m.active = '1'
AND (m.to LIKE '%,".$cms_user['id'].",%' OR m.to = 'all' OR m.from = '".$cms_user['id']."')
GROUP BY m.id
HAVING m.reply = '0'
ORDER BY last_datetime DESC";
foreach($dbh->query($messages_query) as $row_messages){
$messages[] = $row_messages;
$unread_messages_total += (strpos($row_messages['archived'], ','.$cms_user['id'].',') === false && ( (strpos($row_messages['viewed'], ','.$cms_user['id'].',') === false && $row_messages['unread_replies'] == NULL) || ($row_messages['unread_replies']>0 && $row_messages['unread_replies'] != NULL) ) )? 1 : 0;
}
Thanks in advance for any help you can provide!
EDIT: (Database)
CREATE TABLE `cms_messages` (
`id` int(10) NOT NULL auto_increment,
`active` tinyint(1) NOT NULL default '1',
`subject` varchar(255) NOT NULL default '',
`message` text NOT NULL,
`datetime` datetime NOT NULL default '0000-00-00 00:00:00',
`reply` int(10) NOT NULL default '0',
`from` int(10) NOT NULL default '0',
`to` varchar(255) NOT NULL default '',
`viewed` varchar(255) NOT NULL default ',',
`archived` varchar(255) NOT NULL default ',',
PRIMARY KEY (`id`)
) ENGINE=MyISAM AUTO_INCREMENT=1 DEFAULT CHARSET=latin1;
EDIT 2: (Requirements)
- Return all parent messages for a specific
user_id:$cms_user['id'] - Return the number of replies for that parent message:
num_replies - Return the number of unread replies for that parent message:
unread_replies - Return the date of the parent message or it’s most recent reply:
last_datetime - Return whether the message is in the archive:
message_archive - Return whether the message has been viewed:
message_viewed - Return all messages in DESC datetime order
- Return the newest
message, from the parent or replies if there are some (like gmail)
If you have only 2 levels of messages (i.e., only parent messages and direct answers), you might try this query:
It uses subquery
max_reply_idas source of data to select ID of the latest answer. If it exists (i.e., if there are answers),reply_message.messageis used. If it does not exist (no answer has been found for root message), thenroot_message.messageis used.You should also think about structure of table. E.g., it would make more sense if
replycontained eitherNULL, if it is parent message, or ID of existing message. Currently, you set it to0(ID of non-existent message), which is wrong. Types ofviewedandarchivedare also weird.Edit: you should also avoid using
havingclause. Usewhereinstead, when possible.Here’s a new query that should fulfil your requirements. If there is any problem with it (i.e., if it returns wrong data), let me know.
Like the first query, it:
reply_summaryto accumulate data about replies (ID of last reply, number of replies and number of unread replies);cms_messages as reply_messageto the subquery, based onreply_summary.max_reply_id, to get data about the last reply (message, datetime).I’ve simplified the way how you determine
last_datetime– it now takes either time of last reply (if there is any reply), or time of original post (when no replies are found).I have not filtered replies by
fromandtofields. If it is necessary,whereclause ofreply_summarysubquery should be updated.