Laravel/Eloquent如何从同一列返回两个日期范围的求和结果
解决Laravel Eloquent同一SKU多时间段采购总量统计问题
错误分析
你的写法存在两个核心问题:
- 多次调用
selectRaw会覆盖之前定义的查询字段,最终只会保留最后一个selectRaw的结果; - 多次
whereBetween会让查询条件取交集,相当于要求记录同时满足7天和30天的时间范围,这显然不符合需求。
正确实现方案
要在同一查询中统计同一SKU在两个时间段的采购总量,需要用条件聚合(SUM搭配CASE WHEN)来实现,同时用Carbon快速计算时间范围(Laravel默认集成Carbon)。
代码示例(假设Date字段为日期类型)
use Carbon\Carbon; // 计算时间边界:取当前时间的0点和23:59:59 $todayEnd = Carbon::now()->endOfDay(); $sevenDaysAgo = Carbon::now()->subDays(7)->startOfDay(); $thirtyDaysAgo = Carbon::now()->subDays(30)->startOfDay(); $skuStats = Orders::groupBy('SKU') ->selectRaw(' SKU, SUM(CASE WHEN `Date` BETWEEN ? AND ? THEN Quantity ELSE 0 END) as total_last_7_days, SUM(CASE WHEN `Date` BETWEEN ? AND ? THEN Quantity ELSE 0 END) as total_last_30_days ', [$sevenDaysAgo, $todayEnd, $thirtyDaysAgo, $todayEnd]) ->get();
针对字符串格式日期的适配(如示例中的07-23-2022)
如果你的Date字段是字符串类型(月-日-年格式),需要先转换为数据库可识别的日期格式(以MySQL为例,用STR_TO_DATE函数):
$skuStats = Orders::groupBy('SKU') ->selectRaw(' SKU, SUM(CASE WHEN STR_TO_DATE(`Date`, "%m-%d-%Y") BETWEEN ? AND ? THEN Quantity ELSE 0 END) as total_last_7_days, SUM(CASE WHEN STR_TO_DATE(`Date`, "%m-%d-%Y") BETWEEN ? AND ? THEN Quantity ELSE 0 END) as total_last_30_days ', [$sevenDaysAgo, $todayEnd, $thirtyDaysAgo, $todayEnd]) ->get();
关键说明
- 条件聚合通过
CASE WHEN判断每条记录是否属于目标时间段,符合条件则累加Quantity,否则加0; - 使用参数绑定(
?)避免SQL注入,同时让Laravel自动处理日期格式转换; groupBy('SKU')确保每个SKU只返回一行数据,包含两个时间段的统计结果。
推荐搜索关键词
- Laravel Eloquent 条件聚合 sum case when
- Laravel 同一查询多时间段统计
- Eloquent group by 多维度统计
内容的提问来源于stack exchange,提问作者David-Dj Bryant
相关产品推荐
相关产品推荐

