本文介绍在 laravel 8+ 中,如何对一对多关系(如 buyer → orders)执行带时间条件的聚合查询,一次性获取关联记录数、指定列(如 price、charge)的条件求和,并确保查询高效且语法简洁。
本文介绍在 laravel 8+ 中,如何对一对多关系(如 buyer → orders)执行带时间条件的聚合查询,一次性获取关联记录数、指定列(如 price、charge)的条件求和,并确保查询高效且语法简洁。
在构建电商或订单管理系统时,常需从主模型(如 Buyer)出发,同时获取其关联子表(如 orders)的多项统计指标——不仅包括记录数量,还需对多个数值字段(如 price 和 charge)按相同业务条件(例如“近30天内”)分别求和。Laravel 8 引入的 withSum() 方法为此类需求提供了原生、优雅的解决方案。
✅ 正确用法:withCount() + 多次 withSum()
假设你已定义好 Buyer 模型的 orders 关系(hasMany(Order::class)),并有一个 $dateTo 时间变量(如 Carbon::now()->subDays(30)),可直接使用以下链式查询:
$buyers = Buyer::withCount([
'orders' => fn ($query) => $query->where('created_at', '>=', $dateTo)
])
->withSum([
'orders' => fn ($query) => $query->where('created_at', '>=', $dateTo)
], 'price')
->withSum([
'orders' => fn ($query) => $query->where('created_at', '>=', $dateTo)
], 'charge')
->get();
执行后,每个 Buyer 实例将自动附加以下属性:
- orders_count(满足时间条件的订单数)
- orders_price_sum(该买家在指定时间段内所有订单的 price 总和)
- orders_charge_sum(同时间段内所有订单的 charge 总和)
? 注意:withSum() 的第二个参数仅支持单列名(字符串),如需计算表达式(如 price + charge),需改用 selectRaw() + join() 或 DB::raw() 配合子查询,但会牺牲 Eloquent 的关系抽象优势。
Laravel 13.2.0
PHP中文网提供Laravel 13.2.0版本下载,Laravel框架 是基于 PHP 8.3+ 的高性能框架,官方推荐通过 Composer 安装。它内置 AI SDK、JSON:API Resources 及原生向量搜索,支持属性驱动开发与队列路由,大幅提升开发效率。相比旧版,13.2.0 优化了缓存 TTL 管理与实时通信,无需 Redis 即可横向扩展。作为现代 Web 开发首选,它兼顾安全与极速体验,助您快速构建企业级应用。
下载
⚠️ 关键注意事项
- 版本要求:withSum() 仅在 Laravel 8.0+ 可用;若使用 Laravel 7 或更早版本,需通过 selectSub() 手动构造子查询,或升级框架。
- 闭包变量传递:在箭头函数(fn)中引用外部变量(如 $dateTo)无需显式 use(),但若使用传统匿名函数(function ($query)),必须写成 function ($query) use ($dateTo)。
- 性能优化:上述写法会在单条 SQL 中生成多个关联子查询(SELECT ... (SELECT SUM(...) FROM ...) AS ...),避免 N+1 查询,比循环调用 sum() 更高效。
- 空值处理:当某买家无符合条件的订单时,*_sum 字段将返回 null,建议在视图或 API 响应中做空值转换(如 ?? 0)。
✅ 推荐进阶实践(Laravel 9+)
若需复用同一时间范围逻辑,可将条件封装为本地作用域(Scope)提升可维护性:
// In Buyer model
public function scopeWithRecentOrderStats($query, $dateFrom)
{
return $query
->withCount(['orders' => fn ($q) => $q->where('created_at', '>=', $dateFrom)])
->withSum(['orders' => fn ($q) => $q->where('created_at', '>=', $dateFrom)], 'price')
->withSum(['orders' => fn ($q) => $q->where('created_at', '>=', $dateFrom)], 'charge');
}
// Usage:
$buyers = Buyer::withRecentOrderStats($dateTo)->get();
综上,结合 withCount() 与多次 withSum() 是 Laravel 8+ 中实现“带条件多列关联聚合”的标准、推荐方案——语义清晰、性能可控、代码简洁,是现代 Laravel 应用中处理统计类报表查询的最佳实践之一。