php - Laravel:如何使用 Eloquent 获取关系列的总和
问题描述
如何在不加载整个关系数据的情况下使用预加载获取相关模型的 SUM?
在我的项目中有两个模型,Account
和Transaction
. 账户模型has many
交易。
我的要求是:获取帐户并只加载相关表上的总和。
提供了我当前的代码:在此代码transactions
中急切加载并使用 php 计算总和。但我宁愿不加载整个交易。唯一的要求是sum('amount')
。
表:帐户
| id | name | address | ...
表:交易
| id | account_id | amount | ...
账户.php
/**
* Get the transaction records associated with the account.
*/
public function transactions()
{
return $this->hasMany('App\Models\Transaction', 'account_id');
}
以下代码给出了每个帐户及其交易。
$account = Account::with(['transactions'])->get();
SUM 使用以下公式计算:
foreach ($accounts as $key => $value) {
echo $value->transactions->sum('amount'). " <br />";
}
我已经尝试过这样的事情,但没有奏效。
public function transactions()
{
return $this->hasMany('App\Models\Transaction', 'account_id')->sum('amount;
}
解决方案
你需要子查询来做到这一点。我会告诉你一些解决方案:
解决方案 1
$amountSum = Transaction::selectRaw('sum(amount)') ->whereColumn('account_id', 'accounts.id') ->getQuery(); $accounts = Account::select('accounts.*') ->selectSub($amountSum, 'amount_sum') ->get(); foreach($accounts as $account) { echo $account->amount_sum; }
解决方案 2
为 EloquentBuilder创建一个
withSum
宏。use Illuminate\Support\Str; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Query\Expression; Builder::macro('withSum', function ($columns) { if (empty($columns)) { return $this; } if (is_null($this->query->columns)) { $this->query->select([$this->query->from.'.*']); } $columns = is_array($columns) ? $columns : func_get_args(); $columnAndConstraints = []; foreach ($columns as $name => $constraints) { // If the "name" value is a numeric key, we can assume that no // constraints have been specified. We'll just put an empty // Closure there, so that we can treat them all the same. if (is_numeric($name)) { $name = $constraints; $constraints = static function () { // }; } $columnAndConstraints[$name] = $constraints; } foreach ($columnAndConstraints as $name => $constraints) { $segments = explode(' ', $name); unset($alias); if (count($segments) === 3 && Str::lower($segments[1]) === 'as') { [$name, $alias] = [$segments[0], $segments[2]]; } // Here we'll extract the relation name and the actual column name that's need to sum. $segments = explode('.', $name); $relationName = $segments[0]; $column = $segments[1]; $relation = $this->getRelationWithoutConstraints($relationName); $query = $relation->getRelationExistenceQuery( $relation->getRelated()->newQuery(), $this, new Expression("sum(`$column`)") )->setBindings([], 'select'); $query->callScope($constraints); $query = $query->mergeConstraintsFrom($relation->getQuery())->toBase(); if (count($query->columns) > 1) { $query->columns = [$query->columns[0]]; } // Finally we will add the proper result column alias to the query and run the subselect // statement against the query builder. Then we will return the builder instance back // to the developer for further constraint chaining that needs to take place on it. $column = $alias ?? Str::snake(Str::replaceFirst('.', ' ', $name.'_sum')); $this->selectSub($query, $column); } return $this; });
然后,您可以像使用 时一样使用它
withCount
,只是需要在关系 ( ) 之后添加需要求和的列relation.column
。$accounts = Account::withSum('transactions.amount')->get(); foreach($accounts as $account) { // You can access the sum result using format `relation_column_sum` echo $account->transactions_amount_sum; }
$accounts = Account::withSum(['transactions.amount' => function (Builder $query) { $query->where('status', 'APPROVED'); })->get();
推荐阅读
- background - 如何使 Squarespace 博客部分具有背景图像?
- c - 如何在不使用 .h 中的 extern 的情况下访问其他文件中的静态变量?
- java - 序列化杰克逊设置 pojo 的默认类型
- amazon-elastic-beanstalk - Elastic Beanstalk 和安全机密
- c++ - 将可变大小的多维数组作为函数的参数传递
- android - onActivityResult 在 DialogFragments 中已弃用,但在 Activity 中未弃用
- python - 我的 Binance 流似乎没有打开
- python - 如何声明指向同一对象/引用的静态属性
- mediawiki - MediaWiki 模板:通知导入看起来与 mediawiki 不同
- javascript - 反应子组件不从父值渲染道具