使用UNION合并多表按条件查询Produit表报错如何解决
错误原因
UNION 合并结果集的硬性要求是:所有子查询返回的列数必须完全相同,对应位置的列数据类型必须兼容。你的语句报错根源就在列数不匹配:
- 前两个查询分别关联Produit和Aéro、Produit和Commun:Produit有5个字段,Aéro、Commun各有4个字段,两个查询用
SELECT *都会返回9列,列顺序、类型一致,所以两两合并可以正常运行。 - 第三个查询关联Produit和Flot:Flot本身有9个字段,和Produit联表后
SELECT *会返回14列,和前两个查询的9列数量对不上,三个查询合并时自然会抛出错误。
除此之外你的写法还有两个明显问题:
- 用逗号写隐式联表是过时的写法,可读性差,稍不注意就会生成笛卡尔积导致数据量异常
- 你的需求是获取符合条件的Produit表数据,不需要返回另外三张表的字段,隐式联表带出来的冗余字段不仅没用,还可能产生重复的Produit记录。
正确实现方案
推荐写法:EXISTS判断(性能最好,无重复数据)
不需要做联表,直接判断Produit记录的Unit是否存在于三张表region='FMC'的Unit集合中即可:
SELECT p.* FROM Produit p WHERE EXISTS (SELECT 1 FROM Aéro a WHERE a.Unit = p.Unit AND a.region = 'FMC') OR EXISTS (SELECT 1 FROM Commun c WHERE c.Unit = p.Unit AND c.region = 'FMC') OR EXISTS (SELECT 1 FROM Flot f WHERE f.Unit = p.Unit AND f.region = 'FMC')
如果担心同一张表里有多个同Unit的FMC记录导致结果重复,就在SELECT后面加DISTINCT去重即可。
兼容UNION逻辑的写法
如果要保留UNION的写法,必须保证每个子查询返回的列完全一致——你只需要Produit表的字段,那每个子查询就只查Produit的字段,不要用联表后的SELECT *:
SELECT p.* FROM Produit p INNER JOIN Aéro a ON a.Unit = p.Unit WHERE a.region = 'FMC' UNION SELECT p.* FROM Produit p INNER JOIN Commun c ON c.Unit = p.Unit WHERE c.region = 'FMC' UNION SELECT p.* FROM Produit p INNER JOIN Flot f ON f.Unit = p.Unit WHERE f.region = 'FMC'
这里用UNION而非UNION ALL,会自动对结果去重,刚好符合你需要3条不重复Produit记录的预期。
踩坑提醒:多表联表后用
SELECT *搭配UNION是非常容易出错的习惯,只要任意一个关联表的字段数量有变动,就会触发列数不匹配错误,查询时明确指定需要返回的字段是更稳妥的做法。
内容的提问来源于stack exchange,提问作者Youcef Sennoun
相关产品推荐
相关产品推荐

