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

如何用Laravel Eloquent查询支付总额低于收费总额的发票

实现方案

前提准备

首先确保你的Invoices模型已经定义好对应的一对多关联:

// App\Models\Invoices.php
public function charges()
{
    return $this->hasMany(Charge::class, 'invoice_id', 'id');
}

// 注意如果你的支付表模型名是Payment,关联名建议用复数形式更符合规范
public function payments()
{
    return $this->hasMany(Payment::class, 'invoice_id', 'id');
}

如果你的支付表实际表名是payment而非Laravel默认的payments,记得在Payment模型中指定protected $table = 'payment';即可。


核心查询代码(Laravel 8+ 推荐写法)

直接用Eloquent原生的withSum方法实现,性能和可读性都最优,完全兼容Nova资源的自定义查询逻辑:

Invoices::query()
    // 统计对应 charge 总金额,别名 total_charge
    ->withSum('charges as total_charge', 'amount')
    // 统计对应 payment 总金额,别名 total_payment
    ->withSum('payments as total_payment', 'amount')
    // 筛选支付总金额小于账单总金额的发票,COALESCE 用于处理无关联数据时 null 转 0
    ->havingRaw('COALESCE(total_payment, 0) < COALESCE(total_charge, 0)');

低版本Laravel兼容写法

如果你的Laravel版本低于8,不支持withSum方法,可以用join+聚合的方式实现:

Invoices::query()
    ->selectRaw('invoices.*, SUM(charges.amount) as total_charge, SUM(payments.amount) as total_payment')
    ->leftJoin('charges', 'charges.invoice_id', '=', 'invoices.id')
    ->leftJoin('payments', 'payments.invoice_id', '=', 'invoices.id')
    ->groupBy('invoices.id')
    ->havingRaw('COALESCE(total_payment, 0) < COALESCE(total_charge, 0)');

逻辑说明

  • 用havingRaw而非where是因为聚合计算得到的字段,必须走having子句筛选
  • COALESCE函数的作用是把没有关联数据时返回的null转为0,避免null参与比较时逻辑异常,比如某张发票没有任何支付记录时,总支付金额会按0计算
  • 上述链式调用可以直接放到Nova资源对应的indexQuery等自定义查询方法中使用

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.09.24 17:06:03