MySQL中通过子查询与Union关联两表的问题排查及修正
问题分析
你的原SQL逻辑完全偏离需求:
- 子查询里的
LEFT JOIN部分会返回所有table_1的id(左连接不管是否匹配table_2,都会保留主表的全部记录) - 再通过
UNION ALL追加table_2中deleted='0'的table_1_id,最终子查询结果包含了几乎所有table_1的id,外层查询自然会返回全部主表数据,完全没起到筛选作用。
修正方案
推荐两种简洁且符合需求的写法:
方法1:LEFT JOIN + 条件过滤
SELECT DISTINCT t1.* FROM table_1 t1 LEFT JOIN table_2 t2 ON t1.id = t2.table_1_id WHERE t2.table_1_id IS NULL -- 未出现在子表中的主表数据 OR t2.status = 0; -- 已关联子表且status=0的主表数据
添加DISTINCT是为了避免子表中存在多条关联同一主表id的记录时,主表数据被重复返回;如果你的业务场景不会出现这种情况,可以去掉DISTINCT
方法2:NOT EXISTS + EXISTS 组合判断
SELECT t1.* FROM table_1 t1 WHERE NOT EXISTS ( -- 未出现在子表中的数据 SELECT 1 FROM table_2 t2 WHERE t2.table_1_id = t1.id ) OR EXISTS ( -- 已关联子表且status=0的数据 SELECT 1 FROM table_2 t2 WHERE t2.table_1_id = t1.id AND t2.status = 0 );
这种写法无需去重,因为EXISTS仅做存在性判断,不会导致主表数据重复。
额外补充
如果需要同时过滤子表中已删除的记录(比如只考虑deleted='0'的子表数据),可以在关联条件中追加过滤规则,以方法1为例:
SELECT DISTINCT t1.* FROM table_1 t1 LEFT JOIN table_2 t2 ON t1.id = t2.table_1_id AND t2.deleted = '0' WHERE t2.table_1_id IS NULL OR t2.status = 0;
内容的提问来源于stack exchange,提问作者Ashish Patel
相关产品推荐
相关产品推荐

