2016-03-20 154 views
1

我有一個計算預算分錄(收入/結果/餘額)的非常簡單的任務。可以有成千上萬的條目,我可以在中間改變它們中的任何一個。因此,所有以後的條目餘額都必須重新計算。MySQL程序 - 遞增重新計算行

現在我在PHP中通過迭代所有條目的數組並更新已更改的行來完成此操作。這需要太多時間 - 我的服務器停止響應幾分鐘。

我想這是因爲PHP爲每個入口更新調用MySQL,但對於PHP本身來說,這個數組迭代和重新計算的任務相當便宜。我認爲必須有一種方法可以在MySQL上執行這個任務,所以它可以進行迭代/重新計算/更新,這可能也很便宜。

我根本不是MySQL的專家,但我聽說有存儲過程可能是治癒的。

這裏是我的MySQL(33年5月5日)表:

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(27年3月5日):

//... 
//$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

你測量了需要多長時間? –