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