Laravel Eloquent:如何根据关联表字段值选择特定列?
解决方案
要实现根据project_jobs表的type字段动态选择返回的列,你可以通过以下几种方式实现,优先推荐数据库层面的条件查询以提升效率:
方案一:关联查询时用CASE语句动态选择字段(最优)
直接在关联查询的闭包里使用selectRaw结合SQL的CASE条件,让数据库只返回对应类型的有效字段(非对应类型字段返回NULL),避免冗余数据传输:
$projects = Project::select($project_fields) ->with(['job_overview' => function ($query) { $query->select( 'id', 'type', \DB::raw("CASE WHEN type = 'floor' THEN `column A` ELSE NULL END AS `column A`"), \DB::raw("CASE WHEN type = 'floor' THEN `column B` ELSE NULL END AS `column B`"), \DB::raw("CASE WHEN type = 'floor' THEN `column C` ELSE NULL END AS `column C`"), \DB::raw("CASE WHEN type = 'roof' THEN `column D` ELSE NULL END AS `column D`"), \DB::raw("CASE WHEN type = 'roof' THEN `column E` ELSE NULL END AS `column E`"), \DB::raw("CASE WHEN type = 'roof' THEN `column F` ELSE NULL END AS `column F`") ); }])->get();
该方案仅需一次数据库查询,效率最高,返回结果中对应type的字段会保留有效值,其余字段为NULL。
方案二:查询后通过集合过滤字段
若觉得SQL语句繁琐,可先查询所有关联字段,再在集合层面过滤掉不需要的字段:
$projects = Project::select($project_fields) ->with('job_overview') ->get() ->map(function ($project) { $job = $project->job_overview; if (!$job) { return $project; } $keepFields = match ($job->type) { 'floor' => ['id', 'type', 'column A', 'column B', 'column C'], 'roof' => ['id', 'type', 'column D', 'column E', 'column F'], default => ['id', 'type'] }; $project->job_overview = $job->only($keepFields); return $project; });
该方案代码更直观,但会先查询所有字段再过滤,数据量较大时性能不如方案一。
关于你提到的when条件用法
主查询的when方法仅针对project表的条件判断,无法直接引用关联表job_overview的字段(主查询与关联查询为独立执行的逻辑),因此不能在主查询的when中判断job_overview.type,必须在关联查询的闭包里处理字段选择逻辑。
内容的提问来源于stack exchange,提问作者Jorge Cordero
相关产品推荐
相关产品推荐

