mysql - 在 MySQL 多对多表中获取唯一成员资格

标签 mysql join many-to-many

这里是 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/

相关文章:

mysql-为什么这两个查询返回不同的结果

mysql - 添加 SQL 数据库中的值并使用 PHP 将它们显示在表格中

php - 性能问题 - 在额外的表或 php 数组中保存国家名称和其他属性?

MySQL 使用字段定义来定义 View 中的列

hibernate - 按多对多关系查询时从结果列表中排除项目

php - 将我在 Apache 服务器上的网站传输到 AWS

MySQL 从多个表中选择和最近的记录

mysql - 没有中间表的 Eloquent 多对多关系

symfony - 为什么 Doctrine 迁移尝试在多对多关系上创建 2 个表

python - 将 join 的两列合并为一列的结果