为什么 `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:
发表评论: