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>

それらはすべてうまくグループ化されていますが、正しい順序ではありません。それらはすべてごちゃまぜです。最新のメッセージとの会話が最初になるようにそれらを注文する方法についてのアイデアはありますか?

4

2 に答える 2

0

MySQL では、GROUP BYは暗黙的な を実行しORDER BYます。ORDER BY NULL. _

ただし、特定の順序で行を返す必要がある場合は、クエリに ORDER BY を追加します。

また、MySQL がインライン ビューを処理する方法により、インライン ビューの結果セットが一時的な MyISAM テーブルとして実体化されることに注意してください (MySQL はこれを「派生テーブル」と呼びます)。

あなたのクエリがあなたが期待している結果セットを返しているとは思いません。

「コンボ」の一方の側は tuple によって識別され(to_id,from_id)、コンボの対応する側も inverse tuple によって識別されると仮定し(from_id,to_id)ます。

また、すべてのプライベート メッセージを返したいと仮定します。「グループ化」とは、各コンボを並べ替えて表示し、最新のプライベート メッセージが最初にリストされるようにすることを意味します。

最初に、次のようなクエリを使用し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 インジェクションの問題は脇に置いて、あなたが尋ねた質問に焦点を当てます。

会話の 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

これらの会話のすべてのメッセージを取得したい場合、秘訣は、メッセージ テーブルの行をインライン ビューの会話と照合することです。これにより、メッセージの各行が会話の「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. (from_id,to_id次に、convo の識別子、つまり) タプルに基づいて並べ替えます。(これで、インライン ビューから を含めた本当の理由がより明確になるはずto_idです。(他のオプションは$my_id、結合述語での参照です。)

最後に、行が convo で並べ替えられたら、latest_time_sent を持つ行を最初に並べtime_sentます。

于 2013-07-22T23:35:44.367 に答える