CakePHP как получить промежуточную сумму в сущности с помощью виртуального поля?
У меня есть поле под названием депозит, я пытаюсь создать виртуальное поле под названием баланс. Ниже моего желаемого результата это похоже на цепную сумму.
deposit balance
100 100
300 400
10 410
Я пробовал код ниже в сущности
public $balance = 0;
protected function _getBalance()
{
$this->balance = $this->balance + $this->deposit;
return $this->balance;
}
У меня есть все 0
в балансе.
Я получаю результат, как показано ниже
deposit balance
100 0
300 0
10 0
Как добиться желаемого результата?
1 ответ
Сущность не имеет представления о других сущностях, но это необходимо для того, чтобы она могла подвести итоги баланса.
Здесь мне приходят на ум два решения: а) перебор всех результатов и изменение данных или б) в случае, если ваша СУБД их поддерживает, использование оконных функций для создания промежуточной суммы на уровне SQL.
Если вы перебираете все результаты, вы можете получить доступ к балансу предыдущего результата, вычислить сумму и заполнить balance
соответствующее поле, например, в средстве форматирования результатов:
$query->formatResults(function (\Cake\Collection\CollectionInterface $results) {
$previous = null;
return $results->map(function ($row) use (&$previous) {
if ($previous === null) {
$row['balance'] = $row['deposit'];
} else {
$row['balance'] = $previous['balance'] + $row['deposit'];
}
$previous = $row;
return $row;
});
});
На уровне SQL оконные функции позволяют суммировать предыдущие строки:
$query->select(function (\Cake\ORM\Query $query) {
return [
'deposit',
'balance' => $query
->func()
->sum('deposit')
->over()
->order('id')
->rows(null)
];
});
Это создало бы SELECT
предложение вроде этого:
SELECT
deposit,
(
SUM(deposit) OVER (
ORDER BY id ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
)
) AS balance
где сумма вычисляется по всем предыдущим строкам до текущей строки включительно.
Следует отметить, что оконные функции в построителе поддерживаются только в CakePHP 4.1, в предыдущей версии вам нужно было создавать собственные выражения или передавать необработанный SQL:
$query->select([
'deposit',
'balance' => 'SUM(deposit) OVER (
ORDER BY id ROWS BETWEEN UNBOUNDED PRECEDING AND CURRENT ROW
)'
]);
Смотрите также