28

ユーザー向けのメッセージングシステムを作成しました。これにより、ユーザーは別のユーザーにメッセージを送信できます。彼らが初めて話した場合は、新しい会話が開始されますが、そうでない場合は、古い会話が続行されます。

ユーザーの受信トレイには、ユーザーが他のすべてのユーザーと行ったすべての会話が一覧表示され、最新の投稿が含まれている会話の順に並べられます。

ユーザーは、別のユーザーと1つの会話しかできません。

ユーザーがこれらの会話の1つをクリックすると、最新の投稿が上部に表示された会話全体を表示するページに移動します。つまり、メッセージングチャット機能のようなものです。

私は2つのテーブルを持っています:

  • ユーザー会話
  • ユーザーメッセージ

ユーザー会話

userIdおよびfriendIdとともに、会話IDである自動増分IDが含まれます。

最初の会話を開始する人は常にuserIdと受信者のfriendIdになり、その会話でこれが変わることはありません。

+----+--------+----------+
| id | userId | friendId |
+----+--------+----------+

ユーザーメッセージ

読み取りフラグ、時間、conversationIdとともに、特定のメッセージが含まれます

+----+---------+--------+------+------+----------------+
| id | message | userId | read | time | conversationId |
+----+---------+--------+------+------+----------------+

使い方

ユーザーが別のユーザーにメッセージを送信すると、クエリが実行され、両方のユーザーがuserconversationテーブルに一致するかどうかが確認されます。一致する場合はそれconversationIdが使用され、会話が続行されます。一致しない場合は、一意の。を使用して新しい行が作成されますconversationId

複雑になるところ

これまでのところすべてが順調ですが、すべての会話のメッセージ受信ボックスを最新の投稿で並べ替えて表示する場合、1つのクエリで行うのは難しいです。

会話を一覧表示するには、最初に各会話の最新の投稿を見つける必要がありますが、グループの前に注文することはできないため、2つのテーブルで1つのクエリを実行することは不可能であるため、次を使用する必要があります。

SELECT  
    c.id,
    c.userId,
    c.friendId,
    m2.message,
    m2.read,
    UNIX_TIMESTAMP(m2.time),      
    user1.username,
    user2.username  
FROM 
    (SELECT MAX(m1.id) AS MessageID 
     FROM usermessages m1 
     GROUP BY m1.conversationId) latest_msg

INNER JOIN usermessages m2 ON latest_msg.MessageID = m2.id 
INNER JOIN userconversation c ON m2.conversationId = c.id
INNER JOIN user user1 ON c.userId = user.id
INNER JOIN user user2 ON c.friendId = user.id

WHERE c.userId = :userId OR c.friendId = :userId
ORDER BY m2.id DESC
LIMIT 10

これが最善の方法だとは思いませんが、他の方法も考えられませんか?

データベーステーブルはInnoDBであり、結合を高速化し、データの整合性を向上させるため、2つの自動インクリメント行を使用できません。

userconversationテーブルを削除し、conversationId列に配置する一意のIDを作成する別の方法はありますか?次に、userIdとfriendIdをusermessagesに移動するだけで済みます...しかし、これにより多くの冗長データが作成されますか?

4

13 に答える 13

6

うーん、私はあなたの問題を正しく理解していないかもしれません...しかし、私にとって解決策は非常に簡単です:

SELECT c.*, MAX(m.time) as latest_post 
FROM conversations as c 
INNER JOIN messages as m ON c.id = m.conversation_id
WHERE c.userId = 222 OR c.friendId = 222 
GROUP BY c.id
ORDER BY latest_post DESC

ここに私のテストデータがあります:

会話 :

id  userId  friendId
1   222     333
2   222     444

メッセージ:

id  message     time (Desc)     conversation_id
14  rty     2012-05-14 19:59:55     2
13  cvb     2012-05-14 19:59:51     1
12  dfg     2012-05-14 19:59:46     2
11  ert     2012-05-14 19:59:42     1
1   foo     2012-05-14 19:22:57     2
2   bar     2012-05-14 19:22:57     2
3   foo     2012-05-14 19:14:13     1
8   wer     2012-05-13 19:59:37     2
9   sdf     2012-05-13 19:59:24     1
10  xcv     2012-05-11 19:59:32     2
4   bar     2012-05-10 19:58:06     1
6   zxc     2012-05-08 19:59:17     2
5   asd     2012-05-08 19:58:56     1
7   qwe     2012-05-04 19:59:20     1

クエリ結果:

id  userId  friendId    latest_post
2   222     444     2012-05-14 19:59:55
1   222     333     2012-05-14 19:59:51

そうでない場合は...私の答えを無視してください:P

お役に立てれば

于 2012-05-14T18:16:20.240 に答える
4

現在のすべての機能とワークフローを維持しながら、データを 1 つのテーブルに保持できる方法を求めている場合は、かなり近いと思います。

を別のテーブルへのキーにする代わりconversationIdに、会話を開始したメッセージの ID を指すようにします。これにより、会話を開始したメッセージとその後に続くすべてのメッセージの間に親子関係が作成されます。conversationIdすべての会話を表示できるようにするには、が nullであるすべてのメッセージを選択するだけです。以下は、2 つのメッセージの会話を表したものです。

+----+---------+------+------------------+----------------+--------+----------+
| id | message | read | time             | conversationId | toUser | fromUser |
+----+---------+------+------------------+----------------+--------+----------+
| 1  |  test 1 |  0   | (some timestamp) |  null          |  3     |   4      |
| 2  |  test 2 |  0   | (some timestamp) |   1            |  4     |   3      |
+----+---------+------+------------------+----------------+--------+----------+

会話はユーザー 3 によって開始されました。会話内のすべてのメッセージは でフィルターできますconversationId。この設計の 1 つの制限は、2 人のユーザーしか会話に参加できないことです。

アップデート

次の方法で、会話 ID を指定して最後のメッセージを取得できます。

SELECT id, message 
FROM userMessages 
WHERE conversationId = {conversationId} 
ORDER BY time DESC 
LIMIT 1
于 2012-05-14T18:03:20.687 に答える
3

クエリを簡略化したい場合は、テーブルの最後のメッセージIDを追加する必要がありますuserconversation

ALTER TABLE userconversation ADD lastusermessageid

次に、新しいメッセージを追加するたびに、テーブルのユーザー会話を更新する必要があります。

INSERT INTO userconversation(userId, friendId, lastusermessageid)
VALUES (:userId, :friendId, :lastusermessageid)
ON DUPLICATE KEY UPDATE lastusermessageid = VALUES(lastusermessageid)

最後に、すべての外部キーにインデックスを追加します。

SELECT  
    c.id,
    c.userId,
    c.friendId,
    m.message,
    m.read,
    UNIX_TIMESTAMP(m.time),      
    user1.username,
    user2.username  
FROM 
    userconversation c
    INNER JOIN usermessages m ON c.lastusermessageid = m.id 
    INNER JOIN user user1 ON c.userId = user.id
    INNER JOIN user user2 ON c.friendId = user.id
WHERE 
    c.userId = :userId OR c.friendId = :userId
ORDER BY
    m.id DESC
LIMIT 10
于 2012-05-17T20:56:34.157 に答える
3

ユーザー間の会話が 1 つしかできない場合、専用の会話テーブルを用意する理由がわかりません。このクエリを高速に動作させる(user, message_id)には、これらのフィールドが異なるテーブルにある場合に不可能な複合インデックスが必要です。user_idとに移動friend_iduserconversationsます。これにより、テキスト メッセージを含むテーブルではほとんど問題にならない、 1 レコードあたりのテーブル8バイトが重くなります (-byte 識別子を想定しても)。8

ユーザーごとの会話が少なく、それぞれに多くのメッセージがある場合は、これを使用します。

SELECT  um.*
FROM    (
        (
        SELECT  MAX(id) AS messageId
        FROM    usermessages m1
        WHERE   user_id = :me
        GROUP BY
                friend_id
        ORDER BY
                messageId DESC
        LIMIT 10
        )
        UNION ALL
        (
        SELECT  MAX(id) AS messageId
        FROM    usermessages m1
        WHERE   frient_id = :me
        GROUP BY
                user_id
        ORDER BY
                messageId DESC
        LIMIT 10
        )
        ) q
JOIN    usermessages um
ON      um.id = q.messageId
ORDER BY
        id DESC
LIMIT 10

user_idとに別のインデックスを作成するfriend_id

それぞれのメッセージ数が少ない会話が多数ある場合は、次のクエリを使用します。

(
SELECT  *
FROM    usermessages um
WHERE   user_id = :me
        AND id = 
        (
        SELECT  MAX(id)
        FROM    usermessages umi
        WHERE   umi.user_id = um.user_id
                AND umi.friend_id = um.friend_id
        )
ORDER BY
        id DESC
LIMIT 10
)
UNION ALL
(
SELECT  *
FROM    usermessages um
WHERE   frient_id = :me
        AND id = 
        (
        SELECT  MAX(id)
        FROM    usermessages umi
        WHERE   umi.user_id = um.user_id
                AND umi.friend_id = um.friend_id
        )
ORDER BY
        id DESC
LIMIT 10
)
ORDER BY
        id DESC
LIMIT 10

このクエリの背後にある考え方は、各メッセージが会話の最後であることを確認して、特定のユーザーのすべてのメッセージをたどるというものです。これは、すべての会話の最後のメッセージをすべて並べ替えるよりもはるかに高速です (会話が多数ある場合)。

これを高速に動作させるには、インデックスを作成します

friend_id
user_id, friend_id
于 2012-05-14T18:09:41.340 に答える
3

ユーザーの特定のペアは最大で 1 つの会話を行うことができるため、会話を識別するためだけに別のキーを「発明」する必要はありません。また、あなたの質問の言い回しは、メッセージが常に単一のユーザーに送信されることを示唆しているように見えるので、おそらく次のようなものを使用します。

ここに画像の説明を入力

さて、このモデルについて注意すべき点がいくつかあります。

  • これは、同じ 2 人のユーザー間のメッセージが、SEND_TIME に使用されるタイプによって提供される解決よりも頻繁に生成されないことを前提としています。1
  • メッセージの方向は、USER1_ID と USER2_ID の順序ではなく、別のフラグ (DIRECTION) で決定されます。このように、特定のユーザー間のメッセージは、メッセージの送信者と受信者に関係なく、常に USER1_ID と USER2_ID の同じ組み合わせ (上記の CHECK によって強制されます) を持ちます。これにより、クエリが大幅に簡素化されます。
  • 残念なことに、すべての InnoDB テーブルがクラスター化されているため、セカンダリ インデックスI1は比較的高価です。これを回避する方法はありますが、結果として生じる複雑さはおそらく価値がありません。

このデータ モデルを使用すると、"会話" (ユーザー ペアによって識別される) を最新のメッセージで並べ替えることがかなり簡単になります。例 (1目的のユーザーの USER_ID に置き換えます):

SELECT *
FROM (
    SELECT USER1_ID, USER2_ID, MAX(SEND_TIME) NEWEST
    FROM MESSAGE
    WHERE (USER1_ID = 1 OR USER2_ID = 1)
    GROUP BY USER1_ID, USER2_ID
) Q
ORDER BY NEWEST DESC;

(OR USER2_ID = 1これが副次索引の理由ですI1。)

最新の時刻だけでなく、最新のメッセージも必要な場合は、次のようにすることができます。

SELECT * FROM MESSAGE T1
WHERE
    (USER1_ID = 1 OR USER2_ID = 1)
    AND SEND_TIME = (
        SELECT MAX(SEND_TIME)
        FROM MESSAGE T2
        WHERE
            T1.USER1_ID = T2.USER1_ID
            AND T1.USER2_ID = T2.USER2_ID
    )
ORDER BY SEND_TIME DESC;

SQL Fiddleで遊ぶことができます。


1そうでない場合は、代わりに単調増加 INT を使用できますがSELECT MAX(...)、自動インクリメントは PK サブセットでは機能しないため、自分で行う必要があります。または、単純に PKだけにして、USER1_ID と USER2_ID の両方にセカンダリ インデックスを設定します (幸いなことに、PK の方がスリムなので、それらはよりスリムになります)。

于 2012-05-23T21:00:34.987 に答える
1

このように設定します

テーブルの詳細

conversations (#id, last_message_id)

participation (#uid1, #uid2, conversation_id)

messages (#conversation_id, #id, uid, contents, read, *time)

会話

このテーブルは、主に、(最適化のために)最後の更新の計算フィールドとともに、各会話の新しい識別子を生成するために使用されます。2人のユーザーはこのテーブルから切断され、に移動しましparticipationた。

参加

このテーブルは、双方向の2人のユーザー間の会話を記録します。理由を説明するために、次のキーを見てください。

ALTER TABLE `table` ADD PRIMARY(uid1, uid2);

これは、一意性の適用と単純なルックアップの両方に適していますが、次の動作に注意する必要があります。

  • SELECT * FROM table WHERE uid1=1 AND uid2=2
  • SELECT * FROM table WHERE uid1=1
  • SELECT * FROM table WHERE uid1=1 AND uid2>5
  • SELECT * FROM table WHERE uid2=2

最初の2つのクエリは非常にうまく機能し、MySQLはキーの最初の部分でのIDルックアップも最適化します。3つ目は、キーの2つ目の部分を範囲クエリに使用できるため、かなり良好なパフォーマンスが得られます。最後のクエリは、インデックスが「左バイアス」されているため、全表スキャンを実行するため、まったくうまく機能しません。

メッセージ

このテーブルには、会話ID、送信者ID、コンテンツ、読み取りフラグ、および送信時刻を含む、実際に送信されたメッセージが格納されます。

手術

メッセージの送信

2人のユーザー間の会話がすでに確立されているかどうかを判断するには、participationテーブルにクエリを実行するだけです。

SELECT conversation_id FROM participation WHERE uid1=:sender_id AND uid2=:receiver_id

まだ存在しない場合は、両方のレコードを作成します。

INSERT INTO conversations (last_message_id) VALUES (NULL);
# fetch last insert id here
INSERT INTO participation VALUES (:sender_id, :receiver_id, :conversation_id), (:receiver_id, :sender_id, :conversation_id);
INSERT INTO messages VALUES (:conversation_id, 0, :sender_id, :message_contents, 0, NOW());
UPDATE conversations SET last_message_id=LAST_INSERT_ID() WHERE id = :conversation_id

会話がすでに設定されている場合:INSERT INTO messages VALUES(:conversation_id、0、:sender_id、:message_contents、0、NOW()); 会話の更新SETlast_message_id= LAST_INSERT_ID()WHERE id =:conversation_id

注:常に100%正確である必要はないため、UPDATEステートメントはLOW_PRIORITYとしてスケジュールできます。

会話の概要

これはより単純なクエリになりました:

SELECT other_user.name, m.contents, m.read, c.id
FROM participation AS p
INNER JOIN user AS other_user ON other_user.id = p.uid2
INNER JOIN conversation AS c ON c.id = p.conversation_id
INNER JOIN messages AS m ON m.id = c.last_message_id
WHERE p.uid1 = :user_id
ORDER BY m.time DESC
LIMIT 50

免責事項:私はこれをテストしていませんが、記述はあなたにとって意味があるはずです。

最適化

双方向テーブルを使用するのが良いもう1つの理由は、シャーディングの準備をするためです。これは、関連データを別のデータベース(別のマシン)にプッシュする方法です。特定のルールに基づいて、情報をどこから取得するかを決定します。

次の方法でデータを移動できます。

  1. フィールドparticipationに基づいてテーブルを分割しますuid1
  2. フィールドmessagesに基づいてテーブルを分割しますconversation_id

2つのクエリを実行する必要がある可能性があるため、メッセージの概要はより複雑になります。ただし、これはキャッシュ(極端な場合はドキュメントデータベース)を使用するとある程度軽減できます。

これがあなたに将来の計画に関するいくつかのアイデアを与えることを願っています:)

于 2012-05-24T15:05:50.553 に答える
1

これは、fiverr.comおよびwww.infinitbin.comで使用されています。私はインフィニトビンを独自に開発しました。あなたのような2つのデータベースもあります。受信トレイテーブル:-

+----+--------+----------+-------------+------------+--------------------------------+
| id | useridto | useridfrom | conversation | last_content | lastviewed | datecreated|
+----+--------+----------+-------------+------------+--------------------------------+

このテーブルは非常に重要で、会話/受信ボックスを一覧表示するために使用されます。last_contentフィールドは、会話間の最後のメッセージからの140文字です。lastviewedは整数フィールドであり、会話の他のユーザーがメッセージを読んだ場合、メッセージを最後に送信したユーザーが最後に表示されます。NULLに更新されます。したがって、通知を受け取るには、nullではなく、ログインしているユーザーのIDでもないlastviewedを使用します。

会話フィールドは「userid-userid」であるため、文字列です。ユーザーが会話を開始したかどうかを確認するには、user_idsをハイフンで連結して確認します。

この種のメッセージングシステムは非常に複雑です。

2番目の表は非常に単純です。

+----+--------+----------+-------------+-------+
| id | inboxid | userid | content | datecreated|
+----+--------+----------+-------------+-------+
于 2012-05-20T10:14:38.230 に答える
1

なぜデータを会話に分割するのですか?

私だったら、「usermessages」と呼ばれる 1 つのテーブルを次の形式で使用します。

+----+--------+----------+-------------+------------+--------+
| id | userto | userfrom | timecreated | timeviewed | message|
+----+--------+----------+-------------+------------+--------+

会話は、「userto」列と「userfrom」列の組み合わせによって識別されます。したがって、すべての会話を選択する場合:

SELECT * FROM usermessages 
WHERE (userto = :userto OR userto = :userfrom) 
AND (userfrom = :userfrom OR userfrom = :userto) 
ORDER BY timecreated DESC 
LIMIT 10
于 2012-05-14T18:22:20.713 に答える
1

ユーザー会話テーブルを作成する必要はないと思います。

ユーザーが誰かと 1 回だけ会話できる場合、このスレッドの一意の ID は、userId と friendId の連結です。そこで、usersmessage テーブルの friendId 列を移動します。順序の問題 (friendId-userId は userId-friendId と同じスレッド) は次のように解決できます。

SELECT CONCAT(GREATEST(userId,FriendId),"_",LEAST(userId,FriendId)) AS threadId

現在、GROUP BY threadId の後の最後のメッセージを取得するという問題があります。

DATE とメッセージの間、およびこのフィールドの MAX の後に連結を作成するのは良い解決策だと思います。

簡単にするために、列の日付は DATETIME フィールド ('YYYY-mm-dd H:i:s') であると仮定しますが、FROM_UNIXTIME 関数があるため必要ありません。

したがって、最後のクエリは

SELECT 
        CONCAT(GREATEST(userId,FriendId),"_",LEAST(userId,FriendId)) AS threadId,
        friendId, MAX(date) AS last_date, 
        MAX(CONCAT(date,"|",message)) AS last_date_and_message 

FROM usermessages
WHERE userId = :userId OR friendId = :userId
GROUP BY threadId ORDER BY last_date DESC

フィールド last_date_and_message の結果は次のようになります。

2012-05-18 00:18:54|Hi my friend this is my last message

サーバー側のコードから簡単に解析できます。

于 2012-05-24T17:34:06.020 に答える
1

高速な Facebook のようなメッセージ システムを作成する方法。Arutz Sheva ユーザーによってテストされ、広く使用されています - http://www.inn.co.il (ヘブライ語)。

  1. 「トピック」(会話) テーブルを作成します。

      CREATE TABLE pb_topics(
       t_idint(11) NOT NULL AUTO_INCREMENT,
       t_lastint(11) NOT NULL DEFAULT '0',
       t_userint(11) NOT NULL DEFAULT '0',
      主キー ( t_id)、
      キーlast( t_last)
    ) ENGINE=InnoDB AUTO_INCREMENT=137106342 DEFAULT CHARSET=utf8

  2. ユーザーと会話の間にリンクを作成します。

        CREATE TABLE pb_links(
       l_idint(11) NOT NULL AUTO_INCREMENT,
       l_userint(11) NOT NULL DEFAULT '0',
       l_newint(11) NOT NULL DEFAULT '0',
       l_topicint(11) NOT NULL DEFAULT '0',
       l_visibleint(11) NOT NULLデフォルト '1',
       l_bccint(11) NOT NULL デフォルト '0',
      主キー ( l_id) BTREE を使用して、
      ユニークキーtopic-user( l_topic, l_user),
      キーuser-topicnew( l_user, l_new, l_topic) BTREE を使用して、
      キーuser-topic( l_user, l_visible, l_topic) BTREE を使用
    ) ENGINE=InnoDB AUTO_INCREMENT=64750078 DEFAULT CHARSET=utf8

  3. メッセージを作成する

        CREATE TABLE pb_messages(
       m_idint(11) NOT NULL AUTO_INCREMENT,
       m_fromint(11) NOT NULL,
       m_datedatetime NOT NULL DEFAULT '1987-11-13 00:00:00',
       m_titlevarchar(75) NOT NULL,
       m_contentmediumtext NOT NULL,
       m_topicint(11)ヌルではない、
      主キー ( m_id)、
      キーdate_topic( m_date, m_topic),
      キーtopic_date_from( m_topic, m_date, m_from)
    ) エンジン=InnoDB

会話は 2 人以上の友人と行うことができます (BCC はメールのように追加されましたが、スキップできます)。

新しいメッセージを挿入します: 1. 新しいトピックを作成します 2. ユーザーのリンクを作成します (from/to) 3. メッセージを追加します (4. ユーザー キャッシュ テーブルを更新します - ユーザーはメッセージを持っています)

トピックにメッセージを追加: メッセージを追加

フォルダーを選択:

select 
     z.*, group_concat(u_name) as users_name from
         (select max(m_id) as m_id, m_topic as t_id,  m_From, m_title,m_date, l_new 
              from pb_links as l1, pb_messages 
              where l1.l_user=<user>  and m_from < If(inbox, "<>", "=") > and m_topic=l_topic and l1.l_visible=1 
               group by m_topic order by m_id desc limit " & iPage * 35 & ",35) z
           left join  pb_links l2  on (l2.l_topic=t_id)
           left join  users  on (l_user=u_id and l_bcc=0 and l_user<user>)  
            group by l_topic order by m_date desc;

詳細に:

最初は内部選択です。これは、すべてのメッセージを取得し、リストに表示する最後のメッセージも取得するための最速の方法です (Percona/MariaDB バージョンでもチェックされた他の 7 つのオプションについてチェックしました)。内側の IF も見てください - 受信箱では、最後のメッセージは私以外の誰でもあり、送信箱では反対です。ページングに使用される LIMIT。

外側のものは、トピックごとに1 つのメッセージのみのユーザー リスト (コンマ名の文字列に名前を付けるだけ) と詳細情報を追加するために使用されます。大きな歴史)。

また、ここにヘブライ語で書きました: http://blogs.microsoft.co.il/blogs/moshel/archive/2010/08/12/quot-x-quot.aspx 単純なキャッシュテーブルを作成し、ワークロードを禁止しますビジー メッセージ テーブルからの選択数。

于 2012-05-14T18:05:44.200 に答える
1

現在mysqldbにアクセスできないため、このアプローチはテストしていません。でも、ランキング機能を使えばできると思います。mysql には Oracle の row_number 関数に相当するものがないため、次のようにできると思います。

Select * from (
Select 
    uc.id, 
    uc.user_id, 
    uc.friend_id 
    um.message
    um.read, 
    um.time,
    @rownum := IF(@prev_val = um.conversation_id, @rownum + 1, 1) AS rank,
    @prev_val := um.conversation_id
From
    userconversation uc,
    usermessages um,
    (select @row_num:=1) rows,
    (select @prev_val:='') partitions
Where 
    uc.id=um.conversation_id        
    and c.userId = 222 OR c.friendId = 222 

Order By 
    um.conversation_id,um.id desc
)t where t.rank=1
于 2012-05-22T12:50:30.373 に答える
0

これについて私が考える最も簡単な方法は次のとおりです。

テーブル:

conversation(cid | userId | friendId | last_message_id)
messages(mid | message | userId | read | time | cid)

次に、ユーザーが特定の会話にメッセージを挿入するたびに、last_message_id を更新します。

次に、この単純なクエリを実行します。それはあなたが望むものを与えるでしょう。

SELECT * FROM conversation c, messages m 
WHERE (c.userId='$uid' OR c.friendId='$uid')
AND c.last_msg_id=m.message_id
ORDER BY created_time DESC

$uid は、ログインしているユーザーの ID です。

したがって、実際にこのプロセスが行っていることは次のとおりです。

  1. ログインしているユーザーのすべての会話を表示します。
  2. 最後のメッセージを参照する (したがって、group by は必要ありません)
  3. 最後にメッセージを降順で表示します。
于 2012-06-09T04:59:26.627 に答える
-1

ウォッチャーによって提案された答えを拡張します。

さらに単純化するために、「会話」の概念を削除することを検討する必要があります。

+----+---------+------+------------------+--------+----------+
| id | message | read | time             | toUser | fromUser |
+----+---------+------+------------------+--------+----------+
| 1  |  test 1 |  0   | (some timestamp) |  3     |   4      |
| 2  |  test 2 |  0   | (some timestamp) |  4     |   3      |
+----+---------+------+------------------+--------+----------+

ユーザー123のすべての会話のリスト:

SELECT * FROM (
    SELECT id, message, toUser, fromUser   
    FROM userMessages 
    WHERE toUser = 123 OR fromUser = 123 
    ORDER BY id DESC
) AS internalTable 
GROUP BY toUser, fromUser 

ユーザー123とユーザー456の間の会話全体を一覧表示します。

SELECT * 
FROM userMessages
WHERE (toUser = 123 OR fromUser = 123) 
AND (toUser = 456 OR fromUser = 456)
ORDER BY time DESC
于 2012-05-25T00:30:18.450 に答える