You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.23 13:57:30