使用PHP,MySQL数据的顺序不正确

时间:2013-07-22 22:49:52

标签: php mysql messaging

我的网站上有一个消息系统,我正在尝试将消息分组到对话中,类似于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是第一个吗?

2 个答案:

答案 0 :(得分: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");

答案 1 :(得分:0)

在MySQL中,GROUP BY执行隐式ORDER BY。有时,我们可以通过添加ORDER BY NULL来抑制自动排序来提高性能。

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

另请注意,由于MySQL处理内联视图的方式,内联视图的结果集实现为临时MyISAM表(MySQL称之为“派生表”)。

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

我将假设“convo”的一侧由元组(to_id,from_id)标识,并且convo的相应侧也由反元组(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)元组的内联视图中的行,以及反过来,所以我们得到了康沃尔的两面。

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

最后,一旦行按照convo排序,首先使用latest_time_sent排序,我们也按time_sent排序。