如何在Eloquent的JoinSub子查询中动态添加日期过滤条件?
问题描述
现有一段可正常运行的Eloquent查询代码:
$parts = Part::query() ->select( 'parts.employee_id', 'parts.date_of_part', DB::raw('SUM(parts.time) AS day_total_time') ) ->groupBy('parts.date_of_part', 'parts.employee_id'); $holidays = Holiday::query() ->select( 'holidays.employee_id', 'holidays.date_of_holiday', DB::raw('SUM(holidays.time) AS total_holidays_time') ) ->groupBy('holidays.employee_id'); return User::query() ->select( 'users.name', DB::raw('SUM(works.day_total_time) AS parts_sum_time'), DB::raw('vacaciones.total_holidays_time AS holidays_sum_time') ) ->JoinSub( $parts, 'works', function (JoinClause $join) { $join->on('users.id', '=', 'partes.employee_id'); } ) ->leftJoinSub( $holidays, 'vacaciones', function (JoinClause $join) { $join->on('users.id', '=', 'vacaciones.employee_id'); } ) ->groupBy('users.id');
尝试添加日期过滤时,条件会被加到主查询中,而非对应的子查询内部:
fn(Builder $query, $date): Builder => $query ->whereDate('works.date_of_part', '=', $date) ->whereDate('calendar.date_of_holiday', '=', $date)
需要实现:将日期过滤条件分别添加到JoinSub对应的子查询内部。
解决方案
直接在定义$parts和$holidays这两个子查询Builder的时候,追加whereDate过滤条件即可,无需在主查询中操作。
修改后的子查询代码
// 给parts子查询添加日期过滤 $parts = Part::query() ->select( 'parts.employee_id', 'parts.date_of_part', DB::raw('SUM(parts.time) AS day_total_time') ) ->whereDate('parts.date_of_part', '=', $date) // 子查询内部添加日期条件 ->groupBy('parts.date_of_part', 'parts.employee_id'); // 给holidays子查询添加日期过滤 $holidays = Holiday::query() ->select( 'holidays.employee_id', 'holidays.date_of_holiday', DB::raw('SUM(holidays.time) AS total_holidays_time') ) ->whereDate('holidays.date_of_holiday', '=', $date) // 子查询内部添加日期条件 ->groupBy('holidays.employee_id');
完整可运行代码
如果封装成带参数的函数,完整代码如下(同时修正了原代码中的拼写错误):
use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Query\JoinClause; function getUserTimeStats($date) { $parts = Part::query() ->select( 'parts.employee_id', 'parts.date_of_part', DB::raw('SUM(parts.time) AS day_total_time') ) ->whereDate('parts.date_of_part', '=', $date) ->groupBy('parts.date_of_part', 'parts.employee_id'); $holidays = Holiday::query() ->select( 'holidays.employee_id', 'holidays.date_of_holiday', DB::raw('SUM(holidays.time) AS total_holidays_time') ) ->whereDate('holidays.date_of_holiday', '=', $date) ->groupBy('holidays.employee_id'); return User::query() ->select( 'users.name', DB::raw('SUM(works.day_total_time) AS parts_sum_time'), DB::raw('vacaciones.total_holidays_time AS holidays_sum_time') ) ->JoinSub( $parts, 'works', function (JoinClause $join) { $join->on('users.id', '=', 'works.employee_id'); // 修正原代码中别名拼写错误:partes → works } ) ->leftJoinSub( $holidays, 'vacaciones', function (JoinClause $join) { $join->on('users.id', '=', 'vacaciones.employee_id'); } ) ->groupBy('users.id'); }
关键说明
- 子查询的过滤条件直接追加到对应的Builder实例上,确保逻辑被包含在子查询内部,不会污染主查询的WHERE子句。
- 原代码中
JoinSub闭包内的表别名存在拼写错误(partes应为works),已修正避免查询报错。
内容的提问来源于stack exchange,提问作者Mendizalea
相关产品推荐
相关产品推荐

