web-dev-qa-db-ja.com

トランザクションと一緒に保存するためのランニングバランスの計算

レガシーシステムから残高とトランザクションデータの読み取り専用コピーを置く必要があります。これは、ステートメントの表示/印刷にのみ使用されます。

Balance
| id | member_id | product_id | balance |
|  1 |    100001 |         33 |  975.00 |
|  1 |    100002 |         15 |   10.43 |
|  1 |    100001 |         15 |    0.00 |

Transactions
| id | member_id | product_id |       date |    value | interest |
|  1 |    100001 |         33 | 2014-09-01 |  -100.00 |     0.00 |
|  2 |    100001 |         33 | 2014-08-20 |   600.00 |     0.00 |
|  1 |    100002 |         15 | 2014-06-01 |   -50.00 |     0.00 |
|  2 |    100001 |         15 | 2014-08-20 |  -600.00 |     0.00 |

このデータは読み取り専用であり、レガシーシステムの外部の問題により、データはテーブルから取得され、データが更新されるたびにすべてが再挿入されます。理想的ではなく、レガシーシステムは18か月以内に交換する必要があります。

インポートしたトランザクションデータには、実行中の残高の列がありません。私はこれが必要で、2つのオプションが考えられます。

  1. 各トランザクションに対して計算された残高を保存するのではなく、その場で計算します。これまでのところ、最新の残高から始めて、すべてのトランザクション履歴をさかのぼる必要があるため、アカウントステートメントのページ付けは面倒です。そして、私はこの再帰的なクエリを行うための高速な方法を知りません。

  2. トランザクションのインポート時に実行中の残高を計算し、これを各行に対して保存します。

2つ目は私の好みのオプションです(「2009年3月の声明」を簡単に抽出するため)。ランニングバランスを更新する効率的な方法を考案しようとしているのに行き詰まっています。特定のユーザーのアカウントのすべてのトランザクションをコードで選択し、ループして数値を更新するのが最善の方法です。これはパフォーマンスが良くありません。

これにどう対処しますか?私はMySQLで作業する必要がありますが、サポートしているよりもエレガントなソリューションを見つけることにも興味があります。

4
PeterB

コメントに基づいて回答を試みる

これを行う最も簡単で最速の方法は、セットベースのアプローチを取ることです。このような:

1)NOW()を変数@Nに読み込みます

2)新しいデータをTransactionsにロードします

3)Balanceを次のように更新します。

UPDATE Balance B
INNER JOIN (
  SELECT SUM(value) as value, member_id, product_id 
  FROM Transactions 
  WHERE date >= @N) AS T
ON B.member_id = T.member_id
AND B.product_id = T.product_id
SET B.balance = B.balance + T.value

4)利益

1
Thomas Kejser