如何通过Laravel Eloquent实现带条件的INNER JOIN(不使用DB查询)
解决Laravel Eloquent带条件的INNER JOIN需求
直接用whereHas方法就能实现你要的效果,它是Eloquent专门用来基于关联模型条件过滤主模型的API,底层会生成INNER JOIN语句,正好符合你需要的「只保留满足关联任务条件的项目」的要求,完全不需要写原生SQL。
基础用法示例
假设你要筛选出至少有一个状态为已完成的任务的项目,同时预加载符合条件的任务(避免N+1查询),代码如下:
Project::whereHas('tasks', function ($query) { // 这里写任务表的过滤条件 $query->where('status', 'completed'); })->with(['tasks' => function ($query) { // 如果需要同时过滤预加载的任务数据,重复条件即可 $query->where('status', 'completed'); }])->get();
为什么这个方法可行?
whereHas会自动生成INNER JOIN关联表的SQL,只返回存在满足条件的关联任务的项目,完全是INNER JOIN的行为,不会出现tasks为null的项目。- 搭配
with是为了预加载符合条件的任务数据,避免后续访问每个项目的tasks时触发额外查询。如果不需要预加载关联数据,只保留whereHas部分即可。
组合主表和关联表条件
如果需要同时对主表(projects)和关联表(tasks)加过滤条件,直接链式调用where和whereHas即可:
Project::where('is_active', true) // 主表条件 ->whereHas('tasks', function ($query) { $query->where('status', 'completed') // 关联表条件 ->where('due_date', '>', now()); }) ->with(['tasks' => function ($query) { $query->where('status', 'completed') ->where('due_date', '>', now()); }]) ->get();
多层级关联的扩展用法
如果你的关联是多层级的(比如项目下的任务有子任务),可以用嵌套whereHas实现深层关联的过滤:
Project::whereHas('tasks.subtasks', function ($query) { $query->where('priority', 'high'); })->get();
这个方法比事后遍历数组过滤高效得多,因为过滤逻辑在数据库层面完成,避免了加载不必要的数据到内存中。
内容的提问来源于stack exchange,提问作者vbulash
相关产品推荐
相关产品推荐

