You need to enable JavaScript to run this app. Laravel withSum关联查询如何设置关联whereBetween并按日期排序?
优惠活动
大模型
产品
解决方案
定价
更多

Laravel withSum关联查询如何设置关联whereBetween并按日期排序?

关联查询加日期区间过滤的正确实现

首先要避开两个绝大多数人都会踩的坑:

  • 单独给with预加载加日期过滤,但withSum聚合不做同步过滤的话,会出现预加载的关联数据是指定时间范围的,但sum统计值是全时间的,两个口径完全对不上
  • 直接在主查询链上对关联表的date字段加where条件的话,会自动触发内连接逻辑,把指定时间范围内没有任何预订/支出记录的度假村直接过滤掉,不符合常规业务查询预期——我们通常是要保留所有营业中度假村,哪怕它在区间内没有业务记录,只是关联数据和统计值为0即可。

正确实现代码

先定义好需要筛选的日期区间,把相同的过滤逻辑同步应用到预加载和聚合计算上,保证统计口径统一:

// 可根据业务实际从请求、配置中获取起止时间
$startDate = '2024-01-01';
$endDate = '2024-03-31';

// 抽成公共闭包避免重复写相同逻辑
$dateRangeFilter = function ($query) use ($startDate, $endDate) {
    $query->whereBetween('date', [$startDate, $endDate]);
};

$resorts = Resort::where('status', 1)
    // 预加载带日期过滤的预订关联
    ->with(['bookings' => $dateRangeFilter])
    // 聚合预订金额时应用完全相同的日期过滤
    ->withSum(['bookings' => $dateRangeFilter], 'amount')
    // 预加载带日期过滤的支出关联
    ->with(['expenses' => $dateRangeFilter])
    // 聚合支出金额时应用完全相同的日期过滤
    ->withSum(['expenses' => $dateRangeFilter], 'amount')
    // 如果需要按聚合结果排序,直接用withSum生成的默认字段名即可
    ->orderByDesc('bookings_sum_amount')
    ->get();

补充说明

  • 聚合生成的字段默认命名规则是{关联名}_sum_{被统计字段名},也就是上面代码里的bookings_sum_amount、expenses_sum_amount,不需要额外加别名就能直接用于排序
  • 这种写法不会过滤掉没有区间内业务的度假村,这类度假村的关联集合会是空数组,sum值会是0,符合常规列表统计的需求
  • 如果需要只保留区间内有业务记录的度假村,可以额外加whereHas做关联存在性判断,不会影响预加载和聚合的过滤逻辑

内容的提问来源于stack exchange,提问作者Akshay Ashokan

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.28 17:57:02