2011-06-07 43 views
12

获取最新的消息我有我得到需要的消息系统的主要页面(包括未读邮件数等)的全部信息查询......但当前检索线程的消息。我想扩充下面的查询,以便在每个线程中获取最近的最近的消息。在一个线程

这个查询是非常接近,但我平庸的SQL技能让我从包裹的东西了......

$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; 
} 

预先感谢任何帮助,您可以提供!

编辑:(数据库)

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; 

编辑2:(要求)

  • 返回所有父消息为特定user_id$cms_user['id']
  • 返回答复该数量父母消息:num_replies
  • 返回数字个未读答复,该父消息:unread_replies
  • 返回父消息的日期或者是最近的答复:last_datetime
  • 返回的消息是否是在存档:message_archive
  • 返回的消息是否已经浏览:message_viewed
  • 返回在DESC日期时间顺序
  • 返回最新message所有消息,从父或回复,如果有一些(例如Gmail)
+0

可以附加表模式?以及如何识别最近消息的逻辑。 thanx – yoavmatchulsky 2011-06-29 06:35:10

+0

@yoavmatchulsky - 架构添加。行可以是父消息('reply = 0')或回复('reply = parent_id')。如果没有答复,我想要父消息,否则最近的答复(由datetime DESC排序的那个父消息ID的最新答复)。那有意义吗? – RANGER 2011-06-29 06:46:26

+0

你有很深的嵌套信息吗?或只是一个级别? – yoavmatchulsky 2011-06-29 06:59:18

回答

5

如果你只有2级的消息(也就是,只有父级的消息和直接的答案),你可以试试这个查询:

select 
    root_message.id, 
    root_message.active, 
    root_message.subject, 
    case 
     when max_reply_id.max_id is null then 
      root_message.message 
     else 
      reply_message.message 
    end as message, 
    root_message.datetime, 
    root_message.reply, 
    root_message.from, 
    root_message.to, 
    root_message.viewed, 
    root_message.archived 
from 
    -- basic data 
    cms_messages as root_message 
    -- ID of last reply for every root message 
    left join (
     select 
      max(id) as max_id, 
      reply as parent_id 
     from 
      cms_messages 
     where 
      reply <> 0 
     group by 
      reply 
    ) as max_reply_id on max_reply_id.parent_id = root_message.id            
    left join cms_messages as reply_message on reply_message.id = max_reply_id.max_id 
where 
    root_message.reply = 0 

它使用子查询max_reply_id作为数据源选择的最新ID回答。如果存在(即,如果有答案),则使用reply_message.message。如果它不存在(没有找到根消息的答案),则使用root_message.message

你还应该考虑表格的结构。例如,如果reply包含NULL,如果它是父消息或现有消息的ID,则它会更有意义。目前,您将其设置为0(不存在消息的ID),这是错误的。viewedarchived的类型也很奇怪。

编辑:您还应该避免使用having子句。如有可能,请使用where


下面是可以满足您的需要一个新的查询。如果它有任何问题(即,如果它返回错误的数据),请告诉我。

如同第一查询时,它:

  • 使用子查询reply_summary积累大约答复数据(最后的应答的ID,回复数和未读回复数);
  • 将此子查询连接到基表;
  • cms_messages as reply_message连接到子查询,基于reply_summary.max_reply_id获取有关最后回复(消息,日期时间)的数据。

我已经简化你如何确定last_datetime的方式 - 现在只需最后回复的任何时间(如果有任何回复)原来的职位(当发现任何回复),或者时间。

我还没有筛选过fromto字段的回复。如果有必要,应更新reply_summary子查询的where子句。

select 
    parent_message.id, 
    parent_message.subject, 
    parent_message.message, 
    parent_message.from, 
    parent_message.to, 
    coalesce(reply_summary.num_replies, 0) as num_replies, 
    last_reply_message.datetime as reply_datetime, 
    (parent_message.archived NOT LIKE '%,{$cms_user['id']},%') AS message_archive, 
    (parent_message.viewed LIKE  '%,{$cms_user['id']},%') AS message_viewed, 
    reply_summary.unread_replies, 
    coalesce(last_reply_message.message, parent_message.message) as last_message, 
    coalesce(last_reply_message.datetime, parent_message.datetime) as last_datetime 
from 
    cms_messages as parent_message 
    left join (
     select 
      reply as parent_id, 
      max(id) as last_reply_id, 
      count(*) as num_replies, 
      sum(viewed not like '%,{$cms_user['id']},%') as unread_replies 
     from 
      cms_messages 
     where 
      reply <> 0 and 
      active = 1 
     group by 
      reply 
    ) as reply_summary on reply_summary.parent_id = parent_message.id 
    left join cms_messages as last_reply_message on last_reply_message.id = reply_summary.last_reply_id 
where 
    parent_message.reply = 0 and 
    parent_message.active = 1 and 
    (parent_message.to like '%,{$cms_user['id']},%' or parent_message.to = 'all' or parent_message.from = '{$cms_user['id']}') 
order by 
    last_datetime desc; 
+0

我可以更改回复以允许'NULL'而不是'0',但是您的查询似乎没有像原来那样获取特定于'user_id'的消息。它也不会为每个父项目计算'num_replies' ...我已将最初的需求添加到该帖子。 – RANGER 2011-06-29 18:24:24

+0

您的第一个问题是关于获取“最新消息”而不是原始消息。我给你完美的工作(?)解决方案。要过滤特定用户的消息,只需更新'where'子句。要获得回复数量,可以在'max_reply_id'子查询中(以及当然在主查询中选择的值列表中)包含'select(*)as number_of_replies'。 – binaryLV 2011-07-04 09:42:55

+1

@cbh,如果您需要帮助,请提出要求。如果您需要100%完整的解决方案 - 为此付费。我们没有时间给你100%的解决方案,虽然我们可以给出提示,我们可以帮助解决问题,但你也必须参与其中,而不是仅仅提供需求。 – binaryLV 2011-07-04 09:45:45

2

恐怕你无法用单个查询来解决这个问题。要么你必须使用更多的查询并收集周围代码中的信息,否则你将不得不重新设计你的消息系统的数据库结构(表:线程,帖子等)。如果您决定重新设计数据库结构,则还应该注意处理viewedarchived字段的方式。您使用字段(仅限varchar 255!)的方式可能适用于某些用户,但只要有更多的用户和更高的用户ID,您的消息系统就会崩溃。

+0

感谢您的回应。这适用于用户数量有限的封闭系统,因此255限制不会成为问题。 – RANGER 2011-06-29 18:12:25

3

您的问题是,你只读取M唱片无论什么中的R记录的顺序。

尝试添加

SELECT m.*, r.* 

SELECT r.*, m.* 

,如果你使用的是PDO :: FETCH_ASSOC为您的PDO抓取模式(假设你使用PDO访问数据库),其结果将是一个关联数组,如果结果集包含多个具有相同名称的列,那么PDO :: FETCH_ASSOC将为每个列名返回一个单一值。不知道哪个订单需要主持,所以你不得不同时尝试。

如果您的列按正确的顺序定义,它们将返回r。*值(如果存在),或者如果不存在r记录,则返回m。*值。这是否有意义?这样,无论哪个表(m或r)包含它们,您的结果集都将包含最新记录。

http://www.php.net/manual/en/pdo.constants.php