0

我的网站上有一个消息系统,我正在尝试将消息分组到对话中,类似于 Facebook 的做法。以下是我正在使用的 PHP 代码:

                    <form name="myform" action="<?php echo $_SERVER['PHP_SELF']; ?>" method="post" enctype="multipart/form-data">
   <a href="#new_message" data-toggle="modal" class="btn btn-primary pull-right">New Message </a> <input type="submit" name="deleteBtn" class="btn btn-danger pull-right" id="deleteBtn" value="Delete Selected" />
             <br /><br />    <?php
///////////End take away///////////////////////
// SQL to gather their entire PM list
$sql = mysqli_query($db_conx,"SELECT * FROM (SELECT * FROM private_messages WHERE to_id='$my_id' AND recipientDelete='0' ORDER BY time_sent DESC) AS tmp_table GROUP BY LOWER(from_id)");

while($row = mysqli_fetch_array($sql, MYSQLI_ASSOC)){ 

    $item_date = $row["time_sent"];
    $convertedTime = ($myObject -> convert_datetime($item_date));
    $date = ($myObject -> makeAgo($convertedTime));
    //$date = strftime("%b %d, %Y",strtotime($row['time_sent']));
    if($row['opened'] == "0"){
            $textWeight = 'msgDefault';
    } else {
            $textWeight = 'msgRead';
    }
    $fr_id = $row['from_id'];    
    // SQL - Collect username for sender inside loop
    $ret = mysqli_query($db_conx,"SELECT id, username, firstname, lastname FROM bs_mem_base389 WHERE id='$fr_id' LIMIT 1");
    while($raw = mysqli_fetch_array($ret, MYSQLI_ASSOC)){ $Sid = $raw['id']; $Sname = $raw['username']; $Sfirst = $raw['firstname']; $Slast = $raw['lastname']; 
     if ($Sfirst != "") {$Sname = "$Sfirst $Slast";} } //}

?>



<a href="message.php?id=<?php echo $fr_id; ?>" class="<?php echo $textWeight; ?>">
          <p class="pull-right"><?php echo $date; ?> <input type="checkbox" name="cb<?php echo $row['id']; ?>" id="cb" value="<?php echo $row['id']; ?>" /></p>
          <h4><?php echo $Sname; ?></h4>
          <p><?php echo stripslashes(wordwrap(nl2br($row['message']), 54, "\n", true)); ?></p></a>
<?php
}// Close Main while loop
?></form>

将它们组合在一起很好,但它们的顺序不正确。他们都乱七八糟的。关于如何订购它们以使带有最新消息的 convo 排在第一位的任何想法?

4

2 回答 2

2

改变这个:

$sql = mysqli_query($db_conx,"SELECT * FROM (SELECT * FROM private_messages WHERE to_id='$my_id' AND recipientDelete='0' ORDER BY time_sent DESC) AS tmp_table GROUP BY LOWER(from_id)");

对此:

$sql = mysqli_query($db_conx,"SELECT * FROM (SELECT * FROM private_messages WHERE to_id='$my_id' AND recipientDelete='0' ORDER BY time_sent DESC) AS tmp_table GROUP BY LOWER(from_id) order by time_sent desc");
于 2013-07-22T22:54:42.713 回答
0

在 MySQL 中,GROUP BY执行隐式ORDER BY. 有时,我们可以通过添加ORDER BY NULL.

但是,如果您需要按特定顺序返回的行,则将 ORDER BY 添加到查询中。

另请注意,由于 MySQL 处理内联视图的方式,内联视图的结果集被具体化为临时 MyISAM 表(MySQL 将其称为“派生表”)。

我不相信您的查询会返回您期望的结果集。

我将假设“convo”的一侧由 tuple 标识(to_id,from_id),并且 convo 的相应侧也由 inverse tuple 标识(from_id,to_id)

我还将假设您要返回所有私人消息,并且“分组依据”意味着您希望每个 convo 显示为排序在一起,并且首先列出具有最新私人消息的 convo。

我们可以首先获取time_sent从每个“”发送给我们的最新消息“ from_id”,查询如下:

   SELECT n.from_id
        , n.to_id
        , MAX(n.time_sent) AS latest_time_sent
     FROM private_messages n
    WHERE n.to_id = '$my_id'
      AND n.recipientDelete='0'
    GROUP BY n.from_id, n.to_id
    ORDER BY MAX(n.time_sent) DESC, n.from_id DESC

如果你看到这个,然后想,嘿,我们真的不需要返回to_id列,因为它总是相同的值,你是对的。只要我们可以确保它$my_id不包含一些巧妙的字符串,例如:

$my_id = "14' OR 'a'='a";

当然,$my_id可能包含更邪恶的 SQL 文本,我们可能真的希望避免将其包含在我们的语句中。但我们将把 SQL 注入问题放在一边,专注于您提出的问题。

请注意,如果我们还想考虑“来自”我们的消息,就 convo 的 latest_time_sent 而言,(相反,可以修改此查询来做到这一点。但是,现在,我们假设我们是仅查看最近一次向我们发送消息的时间。

如果我们只想在每个 convo 中获取发送给我们的最新消息,“技巧”是将先前查询的结果集与消息表连接起来,如下所示:

SELECT p.*
  FROM private_messages p
  JOIN ( SELECT n.from_id
              , n.to_id
              , MAX(n.time_sent) AS latest_time_sent
           FROM private_messages n
          WHERE n.to_id = '$my_id'
            AND n.recipientDelete='0'
          GROUP BY n.from_id, n.to_id
          ORDER BY MAX(n.time_sent) DESC
       ) o
    ON o.from_id = p.from_id 
   AND o.to_id = p.to_id 
   AND o.time_sent = p.latest_time_sent
 WHERE p.recipientDelete='0'
 ORDER BY o.latest_time_sent DESC, o.from_id DESC

如果我们想获取这些 convo 中的所有消息,诀窍是将消息表中的行与内联视图中的 convo 匹配,以便消息中的每一行都被 convo 的“latest_time_sent”“标记”。

像这样的东西:

SELECT p.*
  FROM private_messages p
  JOIN ( SELECT n.from_id
              , n.to_id
              , MAX(n.time_sent) AS latest_time_sent
           FROM private_messages n
          WHERE n.to_id = '$my_id'
            AND n.recipientDelete='0'
          GROUP BY n.from_id, n.to_id
          ORDER BY MAX(n.time_sent) DESC
       ) o
    ON ( o.from_id = p.from_id AND o.to_id = p.to_id )
    OR ( o.from_id = p.to_id AND o.to_id = p.from_id )
 WHERE p.recipientDelete='0'
 ORDER BY o.latest_time_sent DESC, o.from_id DESC, p.time_sent DESC

(请注意,我们在recipientDelete列上重复谓词;并且我们正在将消息中的行“匹配”到(from_id,to_id)元组上的内联视图中的行,以及相反的行,因此我们得到了 convo 的两边。

然后,当我们对行进行排序时,我们首先基于latest_time_sent. 接下来,我们根据 convo 的标识符进行排序,即(from_id,to_id) 元组。(现在应该更清楚我们to_id从内联视图中包含的真正原因。(另一个选项将$my_id再次引用,在连接谓词中。)

最后,一旦行按 convo 排序,其中 latest_time_sent 在前,我们也按time_sent.

于 2013-07-22T23:35:44.367 回答