SQL多对多关系查询:如何筛选恰好匹配指定关联项及数量的记录
多对多关联下精确匹配桶内水果组合的查询方案
核心校验逻辑
要筛出刚好只装了2个苹果、1根香蕉、没有其他额外水果的桶,三个判定条件必须同时满足,缺一个都可能返回错误结果:
- 桶内的水果品类总数刚好是2种,不存在苹果、香蕉之外的其他水果
- 桶里必须同时有苹果和香蕉,不能缺任意一种
- 两种水果的数量完全对得上:苹果2个,香蕉1个
通用SQL实现(兼容绝大多数关系型数据库)
这个写法不依赖任何数据库特有的函数,逻辑严谨可以直接复用,基于题目给出的表结构和示例数据编写:
SELECT b.id, b.name FROM Buckets b INNER JOIN Bucket_Fruit bf ON b.id = bf.bucket_id WHERE -- 先过滤出和目标水果+对应数量匹配的关联记录 (bf.fruit_id = (SELECT id FROM Fruits WHERE name = 'Apple') AND bf.count = 2) OR (bf.fruit_id = (SELECT id FROM Fruits WHERE name = 'Banana') AND bf.count = 1) GROUP BY b.id, b.name HAVING -- 校验1:桶里实际装的总品类数就是2种,直接排除多装了其他水果的桶 (SELECT COUNT(*) FROM Bucket_Fruit bf_total WHERE bf_total.bucket_id = b.id) = 2 -- 校验2:苹果、香蕉两个品类都在桶里,没有缺漏 AND COUNT(*) = 2 -- 校验3:两个品类的存储数量完全匹配要求 AND SUM(CASE WHEN bf.fruit_id = (SELECT id FROM Fruits WHERE name = 'Apple') THEN bf.count ELSE 0 END) = 2 AND SUM(CASE WHEN bf.fruit_id = (SELECT id FROM Fruits WHERE name = 'Banana') THEN bf.count ELSE 0 END) = 1;
简洁写法(适配支持字符串聚合的数据库,比如MySQL、PostgreSQL)
题目里已经给了业务规则兜底:不存在两个桶的水果存储品类、数量完全一致,这种情况下可以用聚合拼接的方式简化代码,查询效率更高:
-- MySQL版本示例 SELECT b.id, b.name FROM Buckets b INNER JOIN Bucket_Fruit bf ON b.id = bf.bucket_id GROUP BY b.id, b.name HAVING GROUP_CONCAT(CONCAT(bf.fruit_id, ':', bf.count) ORDER BY bf.fruit_id) = '1:2,2:1';
这个写法的逻辑很直接:把每个桶里所有「水果ID:对应数量」的组合按固定顺序拼接成字符串,和目标组合拼出来的字符串做精确相等判断,只要字符串完全一致,就说明桶里的水果品类、数量完全符合要求,不会多装也不会少装。
注意:拼接的时候必须加
ORDER BY固定拼接顺序,不然数据库返回记录的顺序是随机的,可能出现内容一样但顺序不对导致匹配失败的问题。
内容的提问来源于stack exchange,提问作者vitech
相关产品推荐
相关产品推荐

