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

如何在Laravel中用单条查询同时获取日期区间及指定日期前的金额总和

Laravel 单查询同时计算两个时间区间数值总和的实现方案

你原有代码的核心问题是Laravel的leftJoin方法仅支持传入一个关联闭包,不能通过传入多个闭包的方式实现多区间求和,这里提供两种可直接落地的实现方案:


方案1:条件聚合(推荐,性能最优)

通过CASE WHEN做条件判断,仅需要关联一次明细表,无需多次子查询,执行效率更高:

use Illuminate\Support\Facades\DB;

// 可灵活替换为变量传参
$startDate = '2021-08-01';
$endDate = '2021-08-31';

$categories = Account::leftJoin('regularvoucherentrydetails', 'regularvoucherentrydetails.account_name', '=', 'accounts.id')
    ->select(
        'accounts.id',
        'accounts.name',
        'accounts.seqnumber',
        'accounts.accounttype',
        'regularvoucherentrydetails.debitcredit',
        // 统计指定日期区间内的金额总和
        DB::raw("SUM(CASE WHEN regularvoucherentrydetails.dates BETWEEN ? AND ? THEN regularvoucherentrydetails.amount ELSE 0 END) as salesrange"),
        // 统计指定起始日期之前的金额总和
        DB::raw("SUM(CASE WHEN regularvoucherentrydetails.dates < ? THEN regularvoucherentrydetails.amount ELSE 0 END) as salesyesterday")
    )
    ->groupBy(
        'accounts.id',
        'accounts.name',
        'accounts.seqnumber',
        'accounts.accounttype',
        'regularvoucherentrydetails.debitcredit'
    )
    ->orderBy('accounts.fullcode', 'asc')
    ->setBindings([$startDate, $endDate, $startDate])
    ->get();

如果你不需要按借贷方向分开统计,把regularvoucherentrydetails.debitcredit从select和groupBy字段中移除即可。


方案2:子查询字段(与你原生SQL思路完全对齐)

如果要完全匹配你最初写的原生SQL子查询逻辑,可以用Laravel的selectSub能力实现:

use Illuminate\Support\Facades\DB;

$startDate = '2021-08-01';
$endDate = '2021-08-31';

// 构建区间求和子查询
$salesRangeSub = DB::table('regularvoucherentrydetails')
    ->selectRaw('SUM(amount)')
    ->whereColumn('account_name', 'accounts.id')
    ->whereBetween('dates', [$startDate, $endDate]);

// 构建区间前置求和子查询
$salesYesterdaySub = DB::table('regularvoucherentrydetails')
    ->selectRaw('SUM(amount)')
    ->whereColumn('account_name', 'accounts.id')
    ->where('dates', '<', $startDate);

$categories = Account::select(
        'id',
        'name',
        'seqnumber',
        'accounttype',
        DB::raw($salesRangeSub->toSql() . ' as salesrange'),
        DB::raw($salesYesterdaySub->toSql() . ' as salesyesterday')
    )
    // 合并子查询的参数绑定,避免SQL注入风险
    ->mergeBindings($salesRangeSub)
    ->mergeBindings($salesYesterdaySub)
    ->groupBy('id', 'name', 'seqnumber', 'accounttype')
    ->orderBy('fullcode', 'asc')
    ->get();

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.10.05 15:06:03