2

たとえば、2人のユーザーがダイレクトメッセージで話しているとすると、メッセージの会話ができます。その会話から最新のメッセージを選択し、メッセージの受信トレイに会話リンクとして表示したいとします。FacebookとTwitterの方法です。メッセージは機能します。次に、最後に送信されたメッセージをクリックして、会話全体を表示できます。

ユーザー間で送信されるすべてのメッセージを含む私のメッセージテーブルは、次の形式です。

sourceUserIdはメッセージを送信したユーザーのID、targetUserIdはメッセージを受信したユーザーのID、bodyはメッセージ、timeはメッセージが送信されたときのタイムスタンプです。私はbodyをabcとして保持しています...そしてこの例を単純にするために時間1234、それらはすべて異なる値です。

+----+--------------+--------------+--------+------+
| id | sourceUserId | targetUserId |  body  | time |
+----+--------------+--------------+--------+------+
| 1  |       1      |       2      | abc... | 1234 |
| 2  |       3      |       1      | abc... | 1234 |
| 3  |       3      |       1      | abc... | 1234 |
| 4  |       1      |       3      | abc... | 1234 |
| 5  |       2      |       1      | abc... | 1234 |
| 6  |       1      |       2      | abc... | 1234 |
| 7  |       3      |       1      | abc... | 1234 |
| 8  |       4      |       1      | abc... | 1234 |
| 9  |       5      |       4      | abc... | 1234 |
| 10 |       3      |       2      | abc... | 1234 |
+----+--------------+--------------+--------+------+

1人のユーザーのすべてのメッセージ(送信および受信)を取得するには、次のクエリを使用します。

SELECT sourceUserId, targetUserId, body,  UNIX_TIMESTAMP(time)  
FROM `usermessages`
WHERE targetUserId = 1
OR sourceUserId = 1
ORDER BY id DESC
LIMIT 10

+----+--------------+--------------+--------+------+
| id | sourceUserId | targetUserId |  body  | time |
+----+--------------+--------------+--------+------+
| 1  |       1      |       2      | abc... | 1234 |
| 2  |       3      |       1      | abc... | 1234 |
| 3  |       3      |       1      | abc... | 1234 |
| 4  |       1      |       3      | abc... | 1234 |
| 5  |       2      |       1      | abc... | 1234 |
| 6  |       1      |       2      | abc... | 1234 |
| 7  |       3      |       1      | abc... | 1234 |
| 8  |       4      |       1      | abc... | 1234 |
+----+--------------+--------------+--------+------+

ただし、2人のユーザー間の会話からの最新のメッセージだけでなく、同じメッセージ会話の複数のインスタンスを返します。たとえば、行2、3、および4はすべてまったく同じ会話を示します。

次のクエリを使用して、targetUserId(ユーザーが受信したメッセージ)に対してのみクエリを機能させることができます。

SELECT sourceUserId, targetUserId, body,  UNIX_TIMESTAMP(time)  
FROM `usermessages`
WHERE targetUserId = 1
GROUP BY sourceUserId
ORDER BY id DESC
LIMIT 10

+----+--------------+--------------+--------+------+
| id | sourceUserId | targetUserId |  body  | time |
+----+--------------+--------------+--------+------+
| 2  |       3      |       1      | abc... | 1234 |
| 5  |       2      |       1      | abc... | 1234 |
| 8  |       4      |       1      | abc... | 1234 |
+----+--------------+--------------+--------+------+

これとは逆に(ユーザーから送信されたメッセージ)、WHEREとGROUPBYが交換されたばかりであることに注意してください。

SELECT sourceUserId, targetUserId, body,  UNIX_TIMESTAMP(time)  
FROM `usermessages`
WHERE sourceUserId = 1
GROUP BY targetUserId
ORDER BY id DESC
LIMIT 10

+----+--------------+--------------+--------+------+
| id | sourceUserId | targetUserId |  body  | time |
+----+--------------+--------------+--------+------+
| 1  |       1      |       2      | abc... | 1234 |
| 4  |       1      |       3      | abc... | 1234 |
+----+--------------+--------------+--------+------+

しかし、2つの結果を組み合わせると、group by targetUserId, sourceUserId1から(2,3,4)までのすべての送信メッセージがグループ化されるため、正しい結果が得られません。

返却したいもの

このようなクエリの擬似コードは次のようになると思います。

SELECT sourceUserId, targetUserId, body,  UNIX_TIMESTAMP(time)  
FROM `usermessages`
WHERE sourceUserId = 1
OR targetUserId = 1
GROUP BY (If targetUserId != 1), (If sourceUserId != 1)
ORDER BY id DESC
LIMIT 10

+----+--------------+--------------+--------+------+
| id | sourceUserId | targetUserId |  body  | time |
+----+--------------+--------------+--------+------+
| 1  |       1      |       2      | abc... | 1234 |
| 2  |       3      |       1      | abc... | 1234 |
| 8  |       4      |       1      | abc... | 1234 |
+----+--------------+--------------+--------+------+
4

1 に答える 1

2

バージョン2これはテストされていません。それはより近いですが、それでも正しくありません...これに取り組んでいるのに時間切れです...

SELECT Um1.sourceUserId, Um1.targetUserId, um1.body,  UNIX_TIMESTAMP(um1.time)  
FROM usermessages um1
WHERE um1.time = 
   (Select max(um1.time) 
    FROM usermessages um2 
    where um1.sourceUserID = um2.sourceUserID 
      and Um1.targetUserID = Um2.targetUserID, 
      and UM1.Body = UM2.body 
      and (targetuserID = 1 or sourceuserID = 1))
Group by Um1.sourceUserId, Um1.targetUserId, um1.body
ORDER BY id DESC
LIMIT 10

バージョン1(ミス)IMOもボディごとにグループ化する必要があります。

SELECT sourceUserId, targetUserId, body,  UNIX_TIMESTAMP(time)  
FROM `usermessages`
WHERE targetUserId = 1
OR sourceUserId = 1
GROUP BY sourceUserId, targetUserId, body,  UNIX_TIMESTAMP(time)
ORDER BY id DESC
LIMIT 10

または明確に使用する

SELECT distinct sourceUserId, targetUserId, body,  UNIX_TIMESTAMP(time)  
FROM `usermessages`
WHERE targetUserId = 1
OR sourceUserId = 1
ORDER BY id DESC
LIMIT 10

問題は、実際には、これらのレコードの本文が異なるか、タイムスタンプが異なることにあると思います。そうでない場合、なぜそれらはテーブルに複製されますか?具体的には、出力にレコード1と6があるのはなぜですか...重複を防ぐ一意のインデックス/ pkがありませんか?

于 2012-05-09T16:52:06.780 に答える