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 参与者进行多次对话:
- 会话 A:用户 1、用户 2、用户 3
- 会话 B:用户 1、用户 2
- 会话 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 和用户 3 之间的对话,它不应该 return relation_id 55,因为其中也有用户 5。
- 与 relation_id 47 相同,因为其中也包含用户 5。
- 它应该只是 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
我正在尝试根据传入的成员对 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 参与者进行多次对话:
- 会话 A:用户 1、用户 2、用户 3
- 会话 B:用户 1、用户 2
- 会话 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 和用户 3 之间的对话,它不应该 return relation_id 55,因为其中也有用户 5。
- 与 relation_id 47 相同,因为其中也包含用户 5。
- 它应该只是 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