2013-07-22 48 views
0

我在我的網站上有一個消息傳遞系統,我試圖將消息分組到對話中,類似於Facebook的做法。以下是我正在使用的PHP代碼:MySQL數據與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

你在select中沒有ORDER BY,在db中沒有固有的順序,你必須明確地設置它 – 2013-07-22 22:51:46

回答

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"); 
+0

就是這樣,謝謝:) – James

0

在MySQL中,GROUP BY執行隱式ORDER BY。有時,我們可以通過添加ORDER BY NULL來抑制自動排序,從而提高性能。

但是,如果您需要以特定順序返回的行,請向查詢添加ORDER BY。

另請注意,由於MySQL進程內嵌視圖的方式,內聯視圖的結果集被物化爲臨時MyISAM表(MySQL稱之爲「派生表」)。

我不相信你的查詢正在返回你期待的結果集。

我打算假設「convo」的一側由元組(to_id,from_id)標識,convo的相應側也由反向元組(from_id,to_id)標識。

我也假設你想要返回所有的私人信息,並且按「分組方式」,你的意思是你希望每個信息框都顯示在一起排序,最先列出最新的私人信息。

我們可以首先從每個「from_id」發送給我們的消息的最新「time_sent」,用這樣的查詢:

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而言(反面,可以修改此查詢來做到這一點。但是,現在我們假設我們只是在最近一次發送消息給我們的時間。

如果我們想要得到的只是在每個康沃發送給我們的最新消息,該「絕招」就是從消息表,以前的查詢,像這樣加入結果集:

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進行匹配,以便來自消息的每一行都被「tagged_」標記爲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排序,我們也通過time_sent訂購