2016-03-20 7 views
1

私は予算項目(収入/結果/残高)を計算するのは非常に些細な作業です。何千ものエントリがあり、私はそれらのいずれかを途中で変更することができます。その結果、後のすべての項目の残高を再計算する必要があります。MySQLの手順 - インクリメンタルに行を再計算する

今はPHPですべてのエントリの配列を繰り返して、変更された行を更新しています。それはあまりにも時間がかかる - 私のサーバーが数分間応答を停止します。

私はPHPがすべてのエントリの更新のためにMySQLを呼び出すため、PHPのために配列の反復と再計算のこのタスクは非常に安いですが起こると思います。私はMySQLでこのタスクを投げる方法がなければならないと思うので、安価かもしれないiteration/recalculation/update自体を行います。

私はMySQLの専門家ではありませんが、治療法の可能性があるストアドプロシージャがあると聞きました。ここで

が私のMySQL(5.5.33)の表である:ここでは

CREATE TABLE `entry` (
    `id` int(11) NOT NULL AUTO_INCREMENT, 
    `date` date DEFAULT NULL, 
    `is_income` tinyint(1) NOT NULL DEFAULT '0', 
    `income` decimal(20,2) DEFAULT NULL, 
    `outcome` decimal(20,2) DEFAULT NULL, 
    `balance` decimal(20,2) DEFAULT NULL, 
    PRIMARY KEY (`id`) 
) 

は私のPHP(5.3.27)である:

//... 
//$DB is a class for operating DB 
$entries = $DB->get_all('entry'); //retrieves all entries from 'entry' table, sorted by date 
$balance = 0; 
foreach ($entries as $e) { 
    if ($e['is_income']) { 
     $balance += $e['income']; 
    } else { 
     $balance -= $e['outcome']; 
    } 
    if ($balance <> $e['balance']) { 
     $e1 = $e; 
     $e1['balance'] = $balance; 
     $DB->update('entry', $e1); //update the row by doing query('UPDATE `entry` ... WHERE id=' . $entry_id); 
    } 
} 

あなたは私の右方向を指すことができますか?ありがとう!

答えて

2

私はあなたが単一のSQL UPDATEクエリでこれを行うことができると思う、手順は必要ありません。

UPDATE entry AS e1 
JOIN (SELECT * FROM entry ORDER BY date) AS e2 ON e1.id = e2.id 
CROSS JOIN (SELECT @balance := 0) AS var 
SET e1.balance = (@balance := @balance + IF(e2.is_income, e2.income, -e2.outcome)) 

@balance変数ユーザがPHP変数$balanceと同じ目的を果たします。 MySQLではUPDATEという複数のテーブルのクエリでORDER BYを使用できないため、サブクエリが必要です。したがって、IDを日付順に生成するサブクエリに参加する必要があります。

+0

ありがとう、Barmar!これは完全なソリューションですか?このクエリを実行するだけですか? –

+1

それはあるはずですが、私はそれをテストしていません。 – Barmar

0

「適切な」方法は、レポートを表示するときに合計を行い、それをテーブルに保存しないことです。

「千」の場合は、パフォーマンス上の問題ではありません。

+0

これは、データが表示されるたびに時間のかかる計算を行う必要があるため、最良の方法ではありません。一度やり、結果を保存してから、それを表示する方がいいです。 –

+0

あなたは所要時間を測定しましたか? –