1

私は過去数時間でこのクエリで立ち往生しました、そして私はそれを理解するのを手伝ってくれる誰かをひどく必要としています。プライベートメッセージシステムを完成させようとしていますが、データベーステーブルで自分自身を失いました。システム用に3つのテーブルを作成しましたが、それらは次のとおりです。

CONVERSATION(**conversation_id**, subject)

CONVERSATION_MEMBER(**conversation_id**, **user_id**, conversation_last_view, conversation_deleted)

CONVERSATION_MESSAGE(**message_id**, conversation_id, user_id, message_date, message_text)

さて、特定のユーザーのすべての会話を取得する関数では、件名と日付を取得し、最後に、話しているユーザーを表示したいと思います。私は次のクエリを書きました:

SELECT
   c.conversation_id,
   c.conversation_subject, 
   MAX(cmes.message_date) AS conversation_last_reply, 
FROM conversation c, conversation_member cmem, conversation_message cmes
WHERE c.conversation_id = cmes.conversation_id
AND c.conversation_id = cmem.conversation_id                          
AND cmem.user_id = {$_SESSION['user_id']}
AND cmem.conversation_deleted = 0
GROUP BY c.conversation_id
ORDER BY conversation_last_reply DESC

そして、ついに私はユーザーの名前と姓(会話の他のユーザー)を取得しようとしていますが、それを行う方法に迷いました。最初のクエリの結果をループしながら会話IDを取得し、ユーザーの名前と名前を返す別の関数を作成しようとしましたが、うまくいきませんでした。

ところで、ユーザーのために私は別のテーブルを持っています...私はあなたに言う必要はないと思います。はい、ありがとうございます。

4

5 に答える 5

2
$sql = "SELECT (user.forename, user.surname, other_fields...)
          FROM conversation
    INNER JOIN conversation_member
            ON conversation.conversation_id = conversation_member.conversation_id
    INNER JOIN conversation_message
            ON conversation.conversation_id = conversation_message.conversation_id
    INNER JOIN users_table /* replace this with the name of your user table */ AS user
            ON user.user_id = conversation_member.user_id
         WHERE user.user_id = :userid
           AND conversation_member.conversation_deleted = 0
      GROUP BY conversation.conversation_id;"

$query = $db->prepare($sql);
$query->bindParam(':userid', $userid, PDO::PARAM_INT);
$query->execute();
$results = $query->fetchAll();
$user = $results[0]["user"]; //stores array of user fields (forename, surname, etc)
于 2012-04-17T23:37:49.613 に答える
1

「conversation_member」テーブルに再度参加する必要があります。今回は、同じ conversation_id と message_id が適用される他のユーザーの ID を選択します。

SELECT
    c.conversation_id,
    c.conversation_subject, 
    MAX(cmes.message_date) AS conversation_last_reply,
    cmem2.user_id AS other_user_id
    CONCAT(usr_tbl.firstname, ' ', usr_tbl.lastname) AS other_user_name
FROM conversation c
    JOIN conversation_member cmem
    JOIN conversation_message cmes
    JOIN conversation_member cmem2
    JOIN users_table usr_tbl

ON  c.conversation_id = cmes.conversation_id 
AND c.conversation_id = cmem.conversation_id                          
AND cmem.user_id = {$_SESSION['user_id']}
AND cmem.conversation_deleted = 0

AND c.conversation_id = cmem2.conversation_id                          
AND cmem2.user_id = {$_SESSION['other_user_id']}
AND cmem2.conversation_deleted = 0

GROUP BY c.conversation_id
ORDER BY conversation_last_reply DESC
于 2012-04-17T23:58:22.933 に答える
1
SELECT
   c.conversation_id,
   c.conversation_subject,
   user.firstname,
   user.lastname,
   MAX(cmes.message_date) AS conversation_last_reply, 
FROM conversation c, conversation_member cmem, conversation_message cmes, user_tablename user
WHERE c.conversation_id = cmes.conversation_id
AND c.conversation_id = cmem.conversation_id                          
AND cmem.user_id = {$_SESSION['user_id']}
AND cmem.conversation_deleted = 0
AND user.user_id_column = whatever.you_used_as_foriegn_key
GROUP BY c.conversation_id
ORDER BY conversation_last_reply DESC

列名がそのようなものであると仮定します

于 2012-04-17T23:29:50.130 に答える
1

残りのクエリを自分で作成できたのに、なぜユーザーの姓名を取得するのに苦労しているのかわかりませんか?

の行に沿って何かを試してください:

SELECT cmem.user_id, u.first_name,  u.last_name, c.conversation_id, c.conversation_subject, MAX(cmes.message_date) AS conversation_last_reply  
FROM conversation c  
INNER JOIN conversation_member cmem on c.conversation_id=cmem.conversation_id  
INNER JOIN conversation_message cmes on c.conversation_id=cmes.conversation_id  
INNER JOIN users u on u.user_id = cmem.user_id
WHERE cmem.user_id = {$_SESSION['user_id']} AND cmem.conversation_deleted = 0  
GROUP BY cmem.user_id, u.first_name, u.last_name, c.conversation_id, c.conversation_subject

さて、これらすべての結合が不要になるように、データベース構造も再検討する必要があると思います。いくつかの問題があります。1 つ目は、データベースが過度に正規化されているようです。会話 ID と件名の 2 つのフィールドしかない別の「会話」テーブルがあるのはなぜですか? 私がこれまでに見たどのメッセージ システムでも、件名は常に表示されるため、件名フィールドを取得するためだけに常に会話テーブルに参加する必要があります。とにかく、会話_idは他のすべてのテーブルにあります。件名フィールドをメッセージ テーブルに追加し、それがすべて保持されている場合は会話テーブルを削除するだけです。正規化は常に良いことではありません。

次に、メッセージを削除するだけでなく、削除済みメッセージにフラグを設定するのはなぜですか? また、削除したメッセージを復元できるメッセージ システムも見たことがありません。少なくとも、何らかの理由でそれらを保持したい場合は、それらをアーカイブテーブルに移動して、実行しているプラ​​イマリテーブルが無意味な「削除された」を解析するパフォーマンスの影響に対処する必要がないようにする必要があります」のエントリ。

最後に、conversation_member テーブルとは何ですか? 私の解釈に基づいて、それは user_id を持っているため、会話のメンバーを表すことになっています。会話の 1 人のメンバーに対して会話削除フラグが存在するのはなぜですか? どちらかといえば、会話テーブルにあるはずです。その改善により、そこに残された唯一のフィールドは conversation_last_view であり、実際には誰も気にしません。より重要なのは、スレッドに投稿された最後のメッセージのタイムスタンプから簡単に導き出せる conversation_last_post です。

最終的に、クエリに追加された姓名のみを表示したい場合は、users テーブルを結合してこれら 2 つのエントリを表示するだけです。私が提供した SQL クエリは、うまくいかない場合でも、あなたを近づけるはずです。データベースをコピーして自分で試すのは面倒です。ただし、将来的に不必要なパフォーマンスの問題が発生しないように、データベースの全体的な設計も考慮する必要があると思います。

于 2012-04-18T00:24:02.280 に答える
0

次の質問に答えるには: 会話内のすべてのユーザーを検索し、現在のユーザーを差し引いたもの:

    SELECT (users.forename, users.surname)
      FROM conversation_members AS members
INNER JOIN users_table AS users
        ON members.user_id = users.user_id
     WHERE members.conversation_id = :conversationid
       AND NOT users.user_id = :userid

:userid現在のユーザーはどこに:conversationidいて、問題の会話はどこにありますか。

于 2012-04-18T01:07:54.717 に答える