トリガー おそらくあなたが欲しいです。ただし、これを適切かつ効率的に機能させるのは醜いでしょう。以前の日付の行を頻繁に挿入する場合は、各行に残高を保存しない方がよいでしょう。代わりに、クエリまたはビュー を使用してください バランスを見つけるために。特定の日付の残高を見つけるには、それを以前の日付の行と結合し、現在のトランザクションIDでグループ化して正味預金を合計します。
CREATE VIEW pettybalance
AS SELECT SUM(older.pc_in - older.pc_out) AS balance,
current.pc_id AS pc_id, -- foreign key
current.pc_date AS `date`
FROM pettycash AS current
JOIN pettycash AS older
ON current.pc_date > older.pc_date
OR (current.pc_date = older.pc_date AND current.pc_id >= older.pc_id)
GROUP BY current.pc_id
;
older.pc_id
も制限します current.pc_id
未満である スキーマとバランス計算に関連するあいまいさを修正するため。 pc_date
以降 は一意ではありません。特定の日付に複数のトランザクションが発生する可能性があります。その場合、各トランザクションの残高はどのようになりますか?ここでは、IDが大きいトランザクションは、IDが小さいが、日付が同じであるトランザクションの後に発生すると想定しています。より正式には、順序付けを使用します
ビューでは、>:
に基づく≥の順序を使用していることに注意してください。
トリガーを正しく機能させようとした後は、試さないことをお勧めします。挿入/更新時の内部テーブルまたは行ロックのため、残高列を新しいテーブルに移動する必要がありますが、これはそれほど面倒ではありません(pettycash
の名前を変更してください)。 pettytransactions
へ 、新しいpettybalance (balance, pc_id)
を作成します テーブルを作成し、pettycash
という名前のビューを作成します pettytransactions
に参加するより およびpettybalance
pc_id
で )。主な問題は、トリガー本体が作成または更新された行ごとに1回実行されるため、非常に非効率になることです。別の方法は、ストアドプロシージャ
を作成することです。 列を更新します。これは、挿入または更新後に呼び出すことができます。残高を取得する場合、プロシージャはビューよりもパフォーマンスが高くなりますが、データベースに処理させるのではなく、プログラマーが残高を更新する必要があるため、より脆弱になります。ビューを使用すると、よりすっきりとしたデザインになります。
DROP PROCEDURE IF EXISTS update_balance;
delimiter ;;
CREATE PROCEDURE update_balance (since DATETIME)
BEGIN
DECLARE sincebal DECIMAL(10,2);
SET sincebal = (
SELECT pc_bal
FROM pettycash AS pc
WHERE pc.pc_date < since
ORDER BY pc.pc_date DESC, pc.pc_id DESC LIMIT 1
);
IF ISNULL(sincebal) THEN
SET sincebal=0.0;
END IF;
UPDATE pettycash AS pc
SET pc_bal=(
SELECT sincebal+SUM(net)
FROM (
SELECT pc_id, pc_in - pc_out AS net, pc_date
FROM pettycash
WHERE since <= pc_date
) AS older
WHERE pc.pc_date > older.pc_date
OR (pc.pc_date = older.pc_date
AND pc.pc_id >= older.pc_id)
) WHERE pc.pc_date >= since;
END;;
delimiter ;
オフトピック
現在のスキーマの問題は、Float
の使用です。 ■金銭的価値を保存します。浮動小数点数の表現方法が原因で、基数10で正確な(つまり、循環小数表現がない)数値は、常に浮動小数点数として正確であるとは限りません。たとえば、0.01(10進数)は、保存すると0.009999999776482582...または0.0100000000000000002081668...に近くなります。基数3の1/3は「0.1」ですが、基数10では0.333333....に似ています。Float
の代わりに 、Decimal
タイプ:
ALTER TABLE pettycash MODIFY pc_in DECIMAL(10,2);
ALTER TABLE pettycash MODIFY pc_out DECIMAL(10,2);
ビューを使用している場合は、pettycash.pc_bal
をドロップします 。ストアドプロシージャを使用してpettycash.pc_bal
を更新する場合 、それも変更する必要があります。