我有一条"消息"数据方案如下所示的用户系统:
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,然后相应地加载消息?
答案 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()
返回的内容中找到这些主题。