如何编写SQL查询提取满足关联表条件的NOTICE_ID
嘿,针对你这个需求,我整理了几种实用的SQL查询方案,你可以根据自己数据库的特性和实际数据情况选择:
方案一:使用NOT EXISTS子查询(推荐,逻辑直观且性能优)
这个方案的核心逻辑是:先锁定NOTICES表中未被删除(removed=0)的记录,再排除掉那些存在关联LINKS未被删除(removed≠1)的notice_id,剩下的就是完全符合要求的结果。
SELECT n.notice_id FROM NOTICES n WHERE n.removed = 0 AND NOT EXISTS ( SELECT 1 FROM LINKS l WHERE l.notice_id = n.notice_id AND l.removed != 1 );
如果你的NOTICES.notice_id、LINKS.notice_id和LINKS.removed字段有建立索引,这个查询的性能会非常好,数据库优化器通常会高效处理这种NOT EXISTS的逻辑。
方案二:使用GROUP BY + HAVING分组统计
这个方案通过分组后统计关联LINKS的removed值范围,来判断所有关联行是否都为removed=1。
仅包含有关联LINKS的notice_id
SELECT l.notice_id FROM NOTICES n JOIN LINKS l ON n.notice_id = l.notice_id WHERE n.removed = 0 GROUP BY l.notice_id HAVING MAX(l.removed) = 1 AND MIN(l.removed) = 1;
这里要求分组内的LINKS的removed最大值和最小值都是1,意味着该分组下所有LINKS行的removed都是1。但这个写法会漏掉没有关联任何LINKS行的notice_id,如果你的需求需要包含这类记录,可以用下面的调整版本:
包含无关联LINKS的notice_id
SELECT n.notice_id FROM NOTICES n LEFT JOIN LINKS l ON n.notice_id = l.notice_id WHERE n.removed = 0 GROUP BY n.notice_id HAVING MAX(COALESCE(l.removed, 1)) = 1 AND MIN(COALESCE(l.removed, 1)) = 1;
用COALESCE把无关联时的NULL值转换成1,这样无关联的notice_id也会被判定为符合条件。
方案三:使用LEFT JOIN + 筛选NULL
这个方案和NOT EXISTS逻辑类似,通过LEFT JOIN查找不符合条件的LINKS行,再筛选出没有匹配到这些行的notice_id:
SELECT n.notice_id FROM NOTICES n LEFT JOIN LINKS l ON n.notice_id = l.notice_id AND l.removed != 1 WHERE n.removed = 0 AND l.notice_id IS NULL;
这里LEFT JOIN的条件是找关联的LINKS中removed≠1的行,最后WHERE子句筛选出没有匹配到这类行的notice_id(即l.notice_id IS NULL),同时保证NOTICES本身是未被删除的。很多数据库会把这种写法和NOT EXISTS优化成相同的执行计划,性能差异不大。
内容的提问来源于stack exchange,提问作者Ralphie Needham

