SQL - 根据成员选择用户对话

SQL - Selecting a users conversation based on members

我正在尝试根据传入的成员对 select 对话制定查询,这可以是很多参与者。

用户可以与同一用户进行多个对话,并且可以重命名对话。

这是我的消息成员table:

CREATE TABLE `messages_members` (
      `relation_id` int(11) NOT NULL,
      `user_id` int(11) NOT NULL,
      `date` datetime NOT NULL,
      `seen` smallint(6) NOT NULL,
      PRIMARY KEY (`relation_id`,`user_id`),
      KEY `seen` (`seen`,`date`)
    ) ENGINE=InnoDB DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci

消息关系table:

CREATE TABLE `messages_relation` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `sender_id` int(11) NOT NULL,
  `date` datetime NOT NULL,
  `name` varchar(255) COLLATE utf8mb4_unicode_ci DEFAULT NULL,
  PRIMARY KEY (`id`)
) ENGINE=InnoDB AUTO_INCREMENT=49 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci

留言table供参考:

CREATE TABLE `messages` (
  `id` int(11) NOT NULL AUTO_INCREMENT,
  `relation_id` int(11) NOT NULL,
  `user_id` int(11) NOT NULL,
  `message` longtext COLLATE utf8mb4_unicode_ci NOT NULL,
  `date` datetime NOT NULL,
  `updated` smallint(6) NOT NULL,
  PRIMARY KEY (`id`),
  KEY `messages` (`relation_id`,`user_id`),
  KEY `date` (`date`)
) ENGINE=InnoDB AUTO_INCREMENT=135 DEFAULT CHARSET=utf8mb4 COLLATE=utf8mb4_unicode_ci

我的最新解决方案无法正常工作,因为它 select 根据传入的成员计数进行了错误的对话。

目前我唯一能想到的就是取消查询的限制,然后遍历每个结果并进行一些检查以查看成员是否与要求的匹配。

我想知道是否有使用查询的更优雅的解决方案。

这是我当前的查询: 编辑:更新了查询,因为它正在正确地进行计数。

  SELECT relation_id AS relation, GROUP_CONCAT(user_id) AS members, COUNT(user_id) AS selected_members,
            (SELECT COUNT(user_id) FROM messages_members WHERE relation_id = relation) AS total_members
            FROM messages_members            
            WHERE user_id IN( ". $inQuery ." )
            GROUP BY relation_id 
            HAVING total_members = ? AND selected_members = ? 

我从数组中传入每个 users_id,以及数组的总数以匹配所有成员。

为了更清楚地尝试解释我正在尝试做什么,可以与 simialir 参与者进行多次对话:

  1. 会话 A:用户 1、用户 2、用户 3
  2. 会话 B:用户 1、用户 2
  3. 会话 C:用户 1、用户 2、用户 5

我正在尝试 select 对话 A 基于传入的三个用户,user1、user2、user3

来自 messages_members table 的一些示例数据: relation_id, user_id, 日期, 看过

relation_id user_id date seen
2 1 2020-11-18 19:16:54.000 0
5 4 2020-11-18 19:53:34.000 0
5 6 2020-11-18 19:53:34.000 0
14 1 2020-11-19 00:02:44.000 0
14 3 2020-11-19 00:02:44.000 0
19 1 2020-11-19 00:16:32.000 0
19 3 2020-11-19 00:16:32.000 0
20 3 2020-11-19 00:17:37.000 0
20 4 2020-11-19 00:17:37.000 0
21 1 2020-11-19 00:18:09.000 0
21 3 2020-11-19 00:18:09.000 0
21 6 2020-11-19 00:18:09.000 0
22 1 2020-11-19 00:18:45.000 0
22 4 2020-11-19 00:18:45.000 0
22 6 2020-11-19 00:18:45.000 0
23 1 2020-11-19 00:19:06.000 0
23 3 2020-11-19 00:19:06.000 0
23 4 2020-11-19 00:19:06.000 0
24 3 2020-11-19 00:19:42.000 0
24 4 2020-11-19 00:19:42.000 0
24 6 2020-11-19 00:19:42.000 0
25 3 2020-11-19 01:41:44.000 0
25 5 2020-11-19 01:41:44.000 0
43 1 2022-02-28 17:38:34.000 0
43 54 2022-02-28 17:38:35.000 0
46 1 2022-03-16 23:24:43.000 0
46 5 2022-03-16 23:24:43.000 0
47 1 2022-03-16 23:25:51.000 0
47 3 2022-03-16 23:25:51.000 0
47 5 2022-03-16 23:25:51.000 0
48 1 2022-03-17 00:19:26.000 0
2 5 2020-11-18 19:16:54.000 1
23 6 2020-11-19 00:19:06.000 1
47 6 2022-03-16 23:25:51.000 1
48 15 2022-03-17 00:19:26.000 1
54 3 2022-03-19 00:19:22.000 1
54 5 2022-03-19 00:19:22.000 1
55 1 2022-03-19 00:23:18.000 1
55 3 2022-03-19 00:23:18.000 1
55 5 2022-03-19 00:23:18.000 1

对于使用上述数据的一些示例,relation_id 是一个对话。

因此使用底部的 3 个示例,

  1. 如果我只想查找用户 1 和用户 3 之间的对话,它不应该 return relation_id 55,因为其中也有用户 5。
  2. 与 relation_id 47 相同,因为其中也包含用户 5。
  3. 它应该只是 return relation_id 14,其中只有 user1 和 user3。 user1 和 user3 之间有更多的对话,但我只想 return 它找到的第一个对话。

我不是 php 人,但像这样的事情 return 只会涉及 user_id 1 和 user_id 3 的对话:

SELECT mm.relation_id
       , GROUP_CONCAT(mm.user_id) AS User_List
FROM   message_members mm
WHERE  mm.user_id IN (1,3) -- find user_id 1 or 3
AND    NOT EXISTS (
         -- Does not involve other user_id's
         SELECT NULL
         FROM   message_members ex
         WHERE  ex.relation_id = mm.relation_id
         AND    ex.user_id NOT IN (1,3) -- exclude user_id 1 or 3
)
GROUP BY mm.relation_id
-- Where "2" is the unique number of users 
-- i.e. Find user 1 and user 2 = 2 distinct user_id's
HAVING COUNT(DISTINCT mm.user_id) = 2
;

结果:

relation_id | User_List
----------: | :--------
         14 | 1,3      
         19 | 1,3      

db<>fiddle here