SQL多表Join查询:如何筛选供应多个品牌的供应商记录
解决方案
你写的基础三表内连接逻辑是对的,直接在原语句上加GROUP BY+HAVING拿不到正确结果,核心原因是分组会把同供应商的多条品牌明细折叠成单行,既不符合SQL语法规范(非分组字段不能直接写在SELECT子句里),也返回不了你要的所有对应品牌明细。下面两种写法都能实现需求:
写法1:子查询预筛选(兼容性最好,新手友好)
先从关联中间表找出所有供货品牌数大于1的供应商ID,再用这个ID集合过滤原明细查询的结果,所有支持SQL的数据库都能跑:
SELECT s.supplier_name, b.brand_name FROM Brand b INNER JOIN Supplier_Brand sb ON b.brand_id = sb.brand_id INNER JOIN Supplier s ON s.supplier_id = sb.supplier_id WHERE s.supplier_id IN ( SELECT supplier_id FROM Supplier_Brand GROUP BY supplier_id HAVING COUNT(DISTINCT brand_id) > 1 );
小提示:
COUNT里加DISTINCT是为了兼容中间表可能存在的重复关联脏数据,如果你的Supplier_Brand表已经给supplier_id和brand_id建了联合唯一约束,直接写COUNT(brand_id)就行,结果完全一致。
写法2:窗口函数实现(适合支持现代SQL的环境)
如果你的数据库是MySQL 8.0及以上、PostgreSQL、SQL Server等支持窗口函数的版本,可以不用子查询,直接在关联时计算每个供应商的合作品牌总数再过滤:
SELECT supplier_name, brand_name FROM ( SELECT s.supplier_name, b.brand_name, COUNT(DISTINCT b.brand_id) OVER (PARTITION BY s.supplier_id) AS total_brand FROM Brand b INNER JOIN Supplier_Brand sb ON b.brand_id = sb.brand_id INNER JOIN Supplier s ON s.supplier_id = sb.supplier_id ) tmp WHERE total_brand > 1;
新手容易踩的坑
- 别直接在原查询末尾硬加
GROUP BY s.supplier_id HAVING COUNT(...) >1:标准SQL要求SELECT子句里只能出现分组字段和聚合函数,强行写非分组的brand_name要么直接报错,要么在开启非严格模式的旧版MySQL里返回随机的品牌值,结果完全不可靠。 - 计数时记得对品牌ID去重,避免中间表重复录入同一条关联关系导致计数虚高。
内容的提问来源于stack exchange,提问作者frankBang
相关产品推荐
相关产品推荐

