uid | obj_id |
---|---|
A | 数学 |
B | 数学 |
A | 语文 |
B | 语文 |
C | 语文 |
D | 语文 |
A | 英语 |
C | 英语 |
A | 体育 |
C | 体育 |
比方 A,B,C,D 学生选了且仅选 的结果集: [语文课]
比方 A 学生 选了且仅选 的结果集是空 [] (因为 A 所选科目还有其他学生。)
比方 A,B 学生 选了且仅选 的结果集是 [数学] (因为语文课还有 C 学生所以不算)
比方 D 学生 选了且仅选 的结果集是空 [] (因为语文课还有 ABC 学生所以不算)
比方 A ,C 学生 选了且仅选 的结果集是 [英语,体育]
1
VersionGod1 2022-05-20 09:47:34 +08:00
我处理这个问题可能会先查询出 X 个学生选择的相同科目,再查出科目对应的 X 个同学,用 Java 进行匹配
|
2
dqzcwxb 2022-05-20 09:54:47 +08:00
有没有可能在代码里写好逻辑?
|
3
zzyphp111 OP 主要考虑的点在于中间数据量巨大, 类似 A 学生这种 ,实际中间流程数据量巨大, 因为他雨露均沾, 最后算出来是空结果, 就感觉代码逻辑写的太邋遢了。
想想有没有什么好的 sql 妙招。 |
4
nuanshen 2022-05-20 10:07:46 +08:00
# 给个 mysql 的,不过不知道数据量多的情况下性能如何
```mysql SELECT t.uids, GROUP_CONCAT( t.obj_id ) obj_ids FROM ( SELECT t.obj_id, GROUP_CONCAT( t.uid ) uids FROM ( # 以下可替换成数据表 SELECT 'A' uid, '数学' obj_id UNION SELECT 'B' uid, '数学' obj_id UNION SELECT 'A' uid, '语文' obj_id UNION SELECT 'B' uid, '语文' obj_id UNION SELECT 'C' uid, '语文' obj_id UNION SELECT 'D' uid, '语文' obj_id UNION SELECT 'A' uid, '英语' obj_id UNION SELECT 'C' uid, '英语' obj_id UNION SELECT 'A' uid, '体育' obj_id UNION SELECT 'C' uid, '体育' obj_id # end ) t GROUP BY t.obj_id ) t GROUP BY t.uids ``` |
5
klo424 2022-05-20 10:19:05 +08:00
按逻辑写的,不保证效率,假设表是 test ,common 是 A/C 两个人共选的课程,HAVING COUNT(1) = 2 代表有 2 条(有几个人就=几,目的是排除 A/C 有一个没有选这课),exc 排除掉其他人选的课。
WITH common AS ( SELECT obj_id FROM test WHERE uid IN ('A','C') GROUP BY obj_id HAVING COUNT(1) = 2 ), exc AS ( SELECT obj_id FROM test WHERE uid NOT IN ('A','C') ) SELECT * FROM test WHERE obj_id IN (SELECT obj_id FROM common) AND obj_id NOT IN (SELECT obj_id FROM exc) |
6
zzyphp111 OP 找到解决方案了 ,在这里多谢 :"flw" 大佬,以及各位想出来的好办法
答案为: select tmp_group.obj_id from (select obj_id, group_concat(uid) as uids from group_tag group by obj_id order by obj_id) as tmp_group where tmp_group.uids = 'A,B'; 一个 sql 搞定,非常漂亮! |
7
finull 2022-05-20 10:24:48 +08:00
这题是有参数输入的啊,输入是 uid 列表
select obj_id from ( select obj_id from `table` group by object_id having count({input}) = 4 ) t where not exists ( select * from `table` where obj_id = t.obj_id and uid not in ( {input} ) ); |
8
eason1874 2022-05-20 10:37:05 +08:00
我的写法:
SELECT `obj_id` FROM `test` WHERE `obj_id` IN (SELECT `obj_id` FROM `test` WHERE `uid` IN ('A','B','C','D') GROUP BY `obj_id` HAVING COUNT(`obj_id`) = 4) GROUP BY `obj_id` HAVING COUNT(`obj_id`) = 4; 有两个 HAVING COUNT 4 ,是查询 uid 的数量,需要随着输入一起变。帖子里有几种写法了,楼主可以测测哪种更快 |
10
zzyphp111 OP @ColinZeb #9 嗯,group_concat 函数要求 对入参需要先排序, 我这边用 go 的 sort 比较方便快捷:
```go sort.Slice(ids, func(i, j int) bool { return ids[i] < ids[j] }) ``` 其次是要注意 mysql 的配置 group_concat_max_len 默认是 1024 长度,如果 uids 的 长度超了需要额外考虑, 或者提前配置 数据库配置参数。 进入 mysql 状态,输入:show variables like 'group_concat_max_len'; |