这里是 MySQL。我正在为我的网络应用程序构建一个 super 简单的聊天功能,并为其制作了以下数据模型:
describe users;
+----------------------------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+----------------------------+---------------------+------+-----+---------+----------------+
| user_id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| username | varchar(36) | NO | UNI | NULL | |
+----------------------------+---------------------+------+-----+---------+----------------+
describe conversations;
+-------------------------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-------------------------+---------------------+------+-----+---------+----------------+
| conversation_id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| conversation_created_on | datetime | NO | | NULL | |
+-------------------------+---------------------+------+-----+---------+----------------+
describe users_x_conversations;
+-----------------------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------------------+---------------------+------+-----+---------+----------------+
| users_x_conversations | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| user_id | bigint(20) unsigned | NO | MUL | NULL | |
| conversation_id | bigint(20) unsigned | NO | MUL | NULL | |
+-----------------------+---------------------+------+-----+---------+----------------+
describe messages;
+-----------------+---------------------+------+-----+---------+----------------+
| Field | Type | Null | Key | Default | Extra |
+-----------------+---------------------+------+-----+---------+----------------+
| message_id | bigint(20) unsigned | NO | PRI | NULL | auto_increment |
| conversation_id | bigint(20) unsigned | NO | MUL | NULL | |
| sender_id | bigint(20) unsigned | NO | MUL | NULL | |
| message_text | text | NO | | NULL | |
| message_sent_at | datetime | NO | | NULL | |
+-----------------+---------------------+------+-----+---------+----------------+
如上所示,对话将是在用户之间来回发送的 1 条以上消息的容器。
我现在正在尝试编写一个查询来确定用户列表是否具有彼此之间的现有对话(我不想允许完全相同的用户列表之间的重复对话)。所以说我的 users_x_conversations
表看起来像:
user_id | conversation_id
------- | --------
1 3
2 3
3 3
1 4
3 4
2 5
我希望能够确定用户 1、2 和 3 都已开始现有对话 (conversation_id = 3
)。
到目前为止,我能想到的最好的查询是:
SELECT *
FROM conversations c
INNER JOIN users_x_conversations uxc
ON c.conversation_id = uxc.conversation_id
WHERE uxc.user_id IN ( 1,2,3 )
但这会返回用户 1、2 和 3 所属的所有对话,而不是他们都参与的单个对话。
有什么地方会出错吗?
最佳答案
SELECT c.*
FROM conversations c
INNER JOIN users_x_conversations uxc
ON c.conversation_id = uxc.conversation_id
WHERE uxc.user_id IN ( 1,2,3 )
GROUP BY c.conversation_id
HAVING COUNT(*) = 3
这将确保 WHERE 条件 uxc.user_id IN ( 1,2,3 )
中的所有三个用户都是对话的成员。但您还需要确保没有其他成员。这可以通过相关的 NOT EXISTS
子查询来完成。
...
GROUP BY c.conversation_id
HAVING COUNT(*) = 3
AND NOT EXISTS (
SELECT *
FROM users_x_conversations uxc1
WHERE uxc1.conversation_id = uxc.conversation_id
AND uxc1.user_id NOT IN ( 1,2,3 )
)
另一种方法是计算对话中的所有用户(在本例中也应为 3
)。
...
GROUP BY c.conversation_id
HAVING COUNT(*) = 3
AND (
SELECT COUNT(*)
FROM users_x_conversations uxc1
WHERE uxc1.conversation_id = uxc.conversation_id
) = 3
关于mysql - 在 MySQL 多对多表中获取唯一成员资格,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/48962576/