在 Laravel 中使用 whereHas 时从子查询中选择 SUM

2022-01-23 00:00:00 subquery mysql laravel laravel-5.4

我有 2 个表,customerscustomer_invoices,我想获取所有客户的发票条件,并选择特定列(customers.id、customer.last_name,以及每个客户发票的 total_price 总和),我有这个查询:

I have 2 tables, customers and customer_invoices, and I want to get all the customers with a condition on their invoices, and select specific columns (customers.id, customers.last_name, and the sum of the total_price of the invoices for each customer), I have this query :

$result = Customer::whereHas('customerInvoices', function(Builder $q) {
            $q->where('customer_invoices.status', 1);
        })->select([
            'customers.id',
            'customers.last_name',
            DB::raw('SUM(customer_invoices.total_price) as sum')
        ])->get();

customerInvoices 是关系:

public function customerInvoices() {

    return $this->hasMany(CustomerInvoice::class);
}

我想使用子查询而不是连接,所以这里我不能选择这个 DB::raw('SUM(customer_invoices.total_price) as sum'),否则我会得到这个当然是错误的:

I want to use subqueries instead of joins, so here I can't select this DB::raw('SUM(customer_invoices.total_price) as sum'), or else I get this error of course :

"SQLSTATE[42S22]: Column not found: 1054 Unknown column 'customer_invoices.total_price' in 'field list' (SQL: select `customers`.`id`, `customers`.`last_name`, SUM(customer_invoices.total_price) as sum from `customers` where exists (select * from `customer_invoices` where `customers`.`id` = `customer_invoices`.`customer_id` and `customer_invoices`.`status` = 1))"

如何在不使用连接的情况下实现这一点?

How can I achieve this without using joins ?

推荐答案

你可以使用 withCount() 从相关模型中获取总和为

You can use withCount() to get sum from related model as

$result = Customer::select([
            'customers.id',
            'customers.last_name'
        ])->withCount([
            'customerInvoices as invoice_sum' => function($query) {
                $query->select(DB::raw('SUM(total_price)'));
            }
        ])->whereHas('customerInvoices', function(Builder $q) {
            $q->where('customer_invoices.status', 1);
        })->get();

另一种获取总和的方法,您可以在 Customer 模型中定义 hasOne() 关系,例如

Another approach to get sum, you can define a hasOne() relation in your Customer model like

public function invoice_sum()
{
    return $this->hasOne(CustomerInvoice::class)
        ->select('customer_id',
            DB::raw('sum(total_price)')
        )->groupBy('customer_id');
}

在查询生成器中

$result = Customer::select([
            'customers.id',
            'customers.last_name',
        ])->with('invoice_sum')
          ->whereHas('customerInvoices', function(Builder $q) {
            $q->where('customer_invoices.status', 1);
        })->get();      

根据 Eloquent : withCount() 会覆盖 get() 上的 $columns先发出 select() 方法,然后使用 with() 函数

As per Eloquent : withCount() overrides the $columns on get() issue first put select() mehtod and then use with() function

相关文章