为什么 `LEFT JOIN` 里的条件不能筛选数据?—— 深入解析及正确用法
2025-02-28
prompt:
return self::find()
->alias('d')
->leftJoin(CSMSubjectRelations::tableName() . ' r', 'd.SubjectId=r.SubjectId AND r.IsDeleted=0 AND r.CSMouldId=:moduleId')
->leftJoin(CSMSubjectRelationFormulas::tableName() . ' f', 'r.Id=f.CSMSubjectRelationId AND f.IsDeleted=0')
->leftJoin(TJDomainSubjectFormulaConfigsSub::tableName() . ' sf', 'f.FormulaId=sf.Id AND sf.ProjectId=:projectId AND sf.ValidMethod=:validMethod AND sf.IsDeleted=0')
->where([
'd.SubjectId' => $subjectIds,
'd.ProjectId' => $params['ProjectId'],
'd.ValidMethod' => $params['EevaluationMethodType'],
'd.CSOType' => $csoType,
'd.IsDeleted' => 0
])
->select('sf.*') // 仅选择所需字段,避免冲突
->distinct()
->params([
':moduleId' => $moduleId,
':projectId' => $params['ProjectId'],
':validMethod' => $params['EevaluationMethodType']
])
->asArray()
->all();
这个语句能仅仅查询出moduleId为指定id的数据么?
答:
你的查询语句中,moduleId
仅在 LEFT JOIN
关联时使用,但并未在 WHERE
条件中直接筛选,因此 可能会查询出其他 moduleId
的数据,因为 LEFT JOIN
允许即使 r.CSMouldId != :moduleId
的数据也进入最终结果集。
解决方法:
如果你的目标是 确保最终查询结果仅包含 moduleId
相关的数据,需要在 WHERE
条件中添加额外的过滤,如下:
return self::find() ->alias('d') ->leftJoin(CSMSubjectRelations::tableName() . ' r', 'd.SubjectId=r.SubjectId AND r.IsDeleted=0') ->leftJoin(CSMSubjectRelationFormulas::tableName() . ' f', 'r.Id=f.CSMSubjectRelationId AND f.IsDeleted=0') ->leftJoin(TJDomainSubjectFormulaConfigsSub::tableName() . ' sf', 'f.FormulaId=sf.Id AND sf.ProjectId=:projectId AND sf.ValidMethod=:validMethod AND sf.IsDeleted=0') ->where([ 'd.SubjectId' => $subjectIds, 'd.ProjectId' => $params['ProjectId'], 'd.ValidMethod' => $params['EevaluationMethodType'], 'd.CSOType' => $csoType, 'd.IsDeleted' => 0, 'r.CSMouldId' => $moduleId // 确保 `moduleId` 仅匹配指定值 ]) ->select('sf.*') ->distinct() ->params([ ':projectId' => $params['ProjectId'], ':validMethod' => $params['EevaluationMethodType'] ]) ->asArray() ->all();
关键修正:
移除
r.CSMouldId=:moduleId
在LEFT JOIN
里的条件:之前
LEFT JOIN
条件仅用于关联,而不会剔除不匹配的数据,可能会导致r.CSMouldId != :moduleId
的记录依然出现在d
过滤的结果中。现在
WHERE
里 直接添加r.CSMouldId = $moduleId
过滤,确保查询结果只包含moduleId
相关数据。params()
里移除:moduleId
:之前
params()
仅用于JOIN
,但WHERE
现在已经是直接的数组形式,不需要额外绑定:moduleId
变量。
结果:
这样修改后,最终返回的 sf.*
结果中,所有数据都确保 moduleId
为指定值,不会出现多余的 moduleId
相关数据。
prompt:
发表评论: