4

データベースにはtransactions列を持つテーブルがあります: account_iddatetransaction_value(符号付き整数)。別のテーブル ( account_value) には、各アカウントの現在の合計値が格納されます。これは、アカウントtransaction_valueごとのすべての の合計です。テーブルのトリガーで更新されtransactionsます (つまり、INSERT、UPDATE、および DELETE を使用してtransactions、トリガーを起動して を変更しaccount_valueます)。

新しい要件は、過去 365 日間のアカウントの合計取引額のみを計算することです。以前の合計ではなく、現在の現在の合計のみが必要です。この値は、 とほぼ同じ頻度で頻繁に要求されますaccount_value

この「スライディング ウィンドウの合計」を効率的に実装するにはどうすればよいでしょうか。新しいテーブルは大丈夫です。毎回1年の範囲を超えて合計するのを避ける方法はありますか?

4

5 に答える 5

2

これは、標準のウィンドウ関数で実行できます。

SELECT account_id,
       sum(transaction_value) over (partition by account_id order by date)
FROM transactions

クローのorder by内側over()は、合計を「スライド合計」にします。

「過去 356 日間のみ」の場合、WHERE 句の行を制限する 2 つ目のクエリが必要になります。

上記はPostgreSQL、Oracle、DB2、および(私が思うに)Teradataで機能します。SQL Server は、ウィンドウ定義で order by をサポートしていません (今後の Denali バージョンでは AFAIK になります)。

于 2012-01-13T09:45:38.247 に答える
1

トランザクション テーブルへの挿入よりもトランザクション テーブルのクエリの方が頻繁に行われる場合は、ビューを使用することをお勧めします。

于 2012-01-13T09:40:43.533 に答える
1

これほど簡単ですか?

SELECT
   SUM(transaction_value), account_id
FROM
   transactions t
WHERE
   -- SQL Server, Sybase       t.DATE >= DATEADD(year, -1, GETDATE())
   -- MySQL            t.DATE >= DATE_SUB(NOW(), INTERVAL 12 MONTH)
GROUP BY
   account_id;

DATE (MySQL) を使用するか、SQL Server でこの方法を使用して、日付式から時刻コンポーネントを削除することができます。

于 2012-01-13T09:31:18.483 に答える
0

既存の各レコードの前年の値を既存のテーブルに入力するには、1 回限りのスクリプトが必要になります。これは、生成された各レコードの前年全体に対して実行する必要があります。

ローリングイヤーの列にデータが入力されたら、前年度を合計する代わりに、前のレコードのローリングイヤーの値に、最後の更新以降のトランザクション値を加えて、1 年間のトランザクション値を引いた値として、新しい各レコードの値を導き出すことができます。前回の更新前と今から 1 年前。

現実的なテスト データに対して両方のアプローチを試して、どちらがより優れたパフォーマンスを発揮するかを確認することをお勧めします。データが比較的まばらな場合は、1 年全体を合計しても少なくとも同様のパフォーマンスが得られると予想されます。各アカウント。

于 2012-01-13T09:41:49.667 に答える
0

使用しているさまざまな SQL によって大きく異なるため、ここでは実際の SQL は避けます。


あなたは、既存の現在の合計を維持するためのトリガーがあると言います。

また、(またはおそらく夜間のプロセス)account_valueテーブルに新しい毎日のレコードが作成されると思います。次に、INSERT、UPDATE、および DELETE がトリガーを起動して、既存の現在の合計に加算または減算しますか?

必要な変更は次のとおりです:
- 新しいフィールド「yearly_value」などを追加します -
既存のフィールドと同じ方法で既存のトリガーを更新します
- gbn のタイプの回答を使用して今日のレコードを作成します (または、 backdate)
- ただし、新しい毎日の記録はそれぞれ少し異なる方法で初期化します...

新しい日に新しい行を挿入するときは、yesterday's value-に初期化する必要がありますthe value 365 days ago。その後の動作は、すでに慣れているものと同じになるはずです。

于 2012-01-13T09:42:05.323 に答える