将含子查询的SQL语句改写为JOIN形式的技术求助
改写方案及说明
首先明确原SQL的逻辑:它要查询所有未在Link_Table中出现过的Table_A记录——因为子查询里的LEFT JOIN Table_B其实不影响结果(子查询只取LK.A_ID,无论是否匹配到Table_B的记录,LK.A_ID都会被保留)。
基础改写(对应原SQL逻辑)
用LEFT JOIN + IS NULL替代NOT IN,避免NOT IN遇到NULL时返回空结果的隐患:
SELECT DISTINCT A.* FROM Table_A A LEFT JOIN Link_Table LK ON A.A_ID = LK.A_ID WHERE LK.A_ID IS NULL
- 加
DISTINCT是为了避免Link_Table中有重复A_ID时导致结果重复;如果Table_A的A_ID是主键,DISTINCT可以省略。
若原需求是排除「在Link_Table且关联到Table_B」的A_ID
如果你的真实需求是要排除那些在Link_Table中存在对应Table_B记录的A_ID(原SQL的子查询写法其实没实现这个逻辑),可以这样改写:
SELECT A.* FROM Table_A A LEFT JOIN ( SELECT DISTINCT LK.A_ID FROM Link_Table LK INNER JOIN Table_B B ON LK.B_ID = B.B_ID ) LK_MATCHED ON A.A_ID = LK_MATCHED.A_ID WHERE LK_MATCHED.A_ID IS NULL
或者用多表JOIN的形式:
SELECT DISTINCT A.* FROM Table_A A LEFT JOIN Link_Table LK ON A.A_ID = LK.A_ID LEFT JOIN Table_B B ON LK.B_ID = B.B_ID WHERE LK.A_ID IS NULL OR B.B_ID IS NULL
关键注意点
NOT IN的隐患:如果子查询返回的A_ID包含NULL,NOT IN会直接返回空结果,而LEFT JOIN + IS NULL不会有这个问题。- 原SQL中的
LEFT JOIN Table_B是冗余的:因为子查询只选取LK的A_ID,无论是否匹配到Table_B,都不会改变子查询的结果集,所以改写时可以直接忽略这部分关联。
内容的提问来源于stack exchange,提问作者Challenge
相关产品推荐
相关产品推荐

