LEFT JOIN返回NULL值求助:AND过滤条件未按预期排除无效数据
解决LEFT JOIN后出现未过滤NULL的问题
嘿,这个问题太典型了——核心是你搞混了LEFT JOIN的ON条件和WHERE条件的作用差异!
先帮你理清楚为什么会出现这种情况:LEFT JOIN的核心逻辑是强制保留左表的所有行,哪怕右表找不到符合ON条件的匹配记录,这时候右表的字段就会返回NULL。你第二个LEFT JOIN里的P.POSITION IN (3, 4, 5)(注:你写的PR.POSITION应该是笔误,正确表别名是P)只是在关联PERSON表时筛选匹配项,当没有符合条件的PERSON记录时,并不会过滤掉CASE和ATTENDANCE的行,而是把P.NAME等字段设为NULL返回,这就是你看到的“本该过滤却返回NULL”的原因。
接下来给你两种解决方案,你可以根据实际需求来选:
方案1:只保留有符合条件PERSON的记录(转成INNER JOIN)
如果你的需求是必须同时存在符合角色的ATTENDANCE和符合职位的PERSON,那直接把第二个LEFT JOIN改成INNER JOIN就行,这样只有匹配到符合条件的PERSON时才会返回该行:
SELECT C.CASE_ID, A.PERSON_ID, P.NAME FROM CASE C LEFT JOIN ATTENDANCE A ON C.CASE_ID = A.CASE_ID AND A.ROLE IN (1, 2) INNER JOIN PERSON P ON A.PERSON_ID = P.PERSON_ID AND P.POSITION IN (3, 4, 5)
方案2:保留ATTENDANCE行,但过滤掉PERSON不符合条件的记录
如果需要保留所有符合角色的ATTENDANCE行,但只显示那些有符合职位PERSON的记录(过滤掉PERSON为NULL的行),就把POSITION的条件移到WHERE子句里:
SELECT C.CASE_ID, A.PERSON_ID, P.NAME FROM CASE C LEFT JOIN ATTENDANCE A ON C.CASE_ID = A.CASE_ID AND A.ROLE IN (1, 2) LEFT JOIN PERSON P ON A.PERSON_ID = P.PERSON_ID WHERE P.POSITION IN (3, 4, 5)
(注:这个写法和方案1的最终效果类似,但逻辑上是先完成LEFT JOIN再做过滤)
额外提示
如果你的需求是保留所有CASE行,即使没有ATTENDANCE或符合条件的PERSON,但只在PERSON符合职位时显示其名称,否则显示NULL,那你原来的写法是正确的——只要修正PR.POSITION的笔误就行:
SELECT C.CASE_ID, A.PERSON_ID, P.NAME FROM CASE C LEFT JOIN ATTENDANCE A ON C.CASE_ID = A.CASE_ID AND A.ROLE IN (1, 2) LEFT JOIN PERSON P ON A.PERSON_ID = P.PERSON_ID AND P.POSITION IN (3, 4, 5)
内容的提问来源于stack exchange,提问作者benilapit




