在一个查询中从对话中选择用户的所有消息

时间:2015-06-09 20:40:27

标签: php mysql

我有一条"消息"数据方案如下所示的用户系统:

Table: Messages - Message_id PRI AI key
Message_id    Message_text   From_user_id   Date   Conversation_ID
1                  'a'            1                     1               
2                  'b'            2                     1
3                  'c'            5                     1
4                  'f'            18                    2
5                  'e'            1                     8

Table:Conversations
Conversation_id   Subject   
1                 'random'
2                  'hi'
8                  'yolo'

Table:Participants
Conversation_ID   User_id   Ignored - TINYINT(1)
      1            1            0                  
      1            2            0
      1            5            1
      2            18           0
      2            223          0
      8            1            0
      8            19           0

它的工作原理是每个对话都有自己的ID,并且该对话下的任何消息都被记录到消息中,其中的对话链接将消息与对话相关联。用户可以忽略"一个对话,因此在参与者中,我们有一个TINYINT列,用于确定用户是否忽略了对话。

我试图获得一个可以首先返回会话行的查询,然后在其下面显示会话中的消息,这些消息都特定于查询用户。 where子句也应该是用户没有忽略对话。所以,如果我们想要找到"对话"以及User_id 1的相应消息,返回结果将是这样的:

Conversation_id   Subject   Message_id   Message_text   From_user_id
      1          'random'      null         null            null
      1                         1            'a'               1
      1                         2            'b'               2
      1                         3            'c'               5
      8            'yolo'     null          null              null   
                                5            'e'               1

基本上在伪代码中,我尝试做的是:

SELECT conversation_id, conversations.subject FROM participants WHERE user_id = '1' AND ignored = 0 LEFT JOIN conversations ON conversations.conversation_id = participants.conversation_id AND participants.ignored = 0
UNION GROUP BY messages.conversation_id
SELECT message_id, message_text, from_user_id FROM messages WHERE messages.conversation_id = conversation.conversation_id

不幸的是,我在UNION小组遇到了困难,因为我无法将所有的成长混合在一起。我一直在尝试在一个查询中执行此操作(因此选择null以弥补对话没有message_text并且消息没有主题的事实),但不知道任何要执行UNION GROUP BY的MySQL代码。是否可以在一个查询中执行此操作,而无需解析PHP中的所有conversation_id,然后相应地加载消息?

2 个答案:

答案 0 :(得分:1)

我相信您可以使用包含子查询的1个查询执行此操作:

SELECT * 
FROM (
    SELECT Conversation_id 
    FROM Participants 
    WHERE User_id = 1 AND Ignored = 0
    GROUP BY Conversation_id
) AS C_IDs 
INNER JOIN Conversations AS C ON C_IDs.Conversation_id = C.Conversation_id
INNER JOIN Messages AS M ON C_IDs.Conversation_id = M.Conversation_id
WHERE C_IDs.Conversation_id = 1

这应返回如下结果:

C_IDs.Conversation_id   C.Conversation_id   C.Subject   M.Message_id    M.Message_text  M.From_user_id  M.Date  M.Conversation_ID
1                       1                   'random'    1               'a'             1                       1
1                       1                   'random'    2               'b'             2                       1
1                       1                   'random'    3               'c'             5                       1

如果在最后删除WHERE子句并更改SELECT:

SELECT C.Conversation_id AS Conversation_id, C.Subject AS Subject, M.Message_id AS Message_id, M.Message_text AS Message_text, M.From_user_id AS From_user_id
FROM (
    SELECT Conversation_id 
    FROM Participants 
    WHERE User_id = 1 AND Ignored = 0
    GROUP BY Conversation_id
) AS C_IDs 
INNER JOIN Conversations AS C ON C_IDs.Conversation_id = C.Conversation_id
INNER JOIN Messages AS M ON C_IDs.Conversation_id = M.Conversation_id

结果应该是这样的:

Conversation_id Subject     Message_id  Message_text    From_user_id
1               'random'    1           'a'             1
1               'random'    2           'b'             2
1               'random'    3           'c'             5
8               'yolo'      5           'e'             1

如果要在结果集中循环显示,只需创建一个跟踪对话ID的变量。将值初始化为NULL,然后添加一个if语句,用于检查值是否已更改。如果有,则写出新的会话详细信息,然后将id设置为新的id。

答案 1 :(得分:0)

恕我直言,这是一个非常糟糕的方式。而不是弄乱那么多,只需要做2个简单的查询。首次查询对话,第二次查询与对话相关的所有消息。假设您正在使用PDO,以下是两个需要的查询:

$q1 = $conn->prepare('SELECT Conversation_ID FROM `participants` WHERE `User_id` = ? AND `Ignored` = 0');

$q1->execute(array($userID));

$conversations = array_map(function($item) { return $item->Conversation_ID; }, $q1->fetchAll());

$q2 = $conn->prepare('SELECT * FROM messages WHERE `Conversation_ID` IN (' . implode(',', $conversations) . ') AND `User_id` != ?');

$q2->execute(array($userID));

$messages = $q2->fetchAll();

此时,$messages包含您想要的所有信息,但会话主题除外,但您可以在$q1->fetchAll()返回的内容中找到这些主题。