リレーショナルデータベースで価格設定の履歴などを追跡する場合、価格設定の変更を保存するために推奨される方法は何ですかたとえば、次のことができます。
price_change_date
または
effective_price_start_date
およびeffective_price_end_date
(別名、新しい価格を入力すると、古いレコードは「終了日」を取得および更新し、新しいレコードは「開始日」として現在の日付を取得し、「[終了日]」はnull
(?)を取得します)。これは、各価格履歴レコードの2つの日付です。私は最初のアプローチを考えています-「これは価格が入力された日付です」を意味する単一の日付レコードのみを保持することで十分です。そして、おそらくメンテナンスが少し簡単です。
しかし、価格の有効期間、つまり価格の開始日と終了日を維持することを推奨する他の回答の提案を見ました。しかし、そのアプローチには次のような複雑な問題があります
null
を配置して「現在アクティブ」と解釈しますか?2番目のアプローチ(レコードごとに2つの日付列)ではなく、最初のアプローチ(1つの日付列)を選択した場合に直面する特定の問題はありますか?
目標
目的は、監査の目的と顧客の質問です。つまり、2015年1月にパートXに対して何を請求しましたか?どうやって見つけるのですか?
または、お客様が注文した昨年と比較して、なぜ200ドル多く請求するのですか?このため、またはそのため、12月に価格を変更しました。
どのように変更が生じるか-1月にパートXに100ドルを請求するように人事部が指示するが、2月からは200ドルを請求するとします。
イベントソーシングを使用したドメインドリブンデザイン は、追記専用のログに記録される不変のエントリを使用してイベントを格納すると言います。発生したイベントのみを保存するため、イベントの日付は1つです(つまり、終了日はありません)。
ただし、おそらくすべての現在の価格も知りたいので、CQRS/ESは、それだけを格納する別のテーブルがどこかにあると言っています。 CQRS/ESの設計では、そのテーブルをキャッシュと呼び、破棄して自由に再構築できます。 (したがって、それらはキャッシュではなくログの強化に集中します。)
現在の価格を保存する場合、現在の価格を1つだけ保存するため、終了日情報は必要ありません。必要に応じて日付を含めることもできますが、古い価格に関する他の計算では、おそらくイベントストア(または他のキャッシュされた情報を保存)に戻る必要があります。
(ところで、イベントストアは同じSQLデータベースでも、別のものでもかまいません。)
これの利点は、不変の追記専用ログがさまざまなテクノロジー(SQL、NoSQL)で簡単であり、現在の日付のみを格納するキャッシュが非常にシンプルなテーブルであることです。
確かに、2番目のアプローチの方が扱いが簡単です。
2番目のアプローチを使用する場合、以前の価格に戻すには、まずビジネスの観点から分析する必要があります。
確定されていない終了日については、2つの学校があります。
オプション1(1行に1つの日付)を使用して特定の日付(現在またはそれ以外)の価格を見つけるには、複数のレコードを順番に読み取る必要があるという点で@Christopheに同意します(データベースエンジンがそれを行うので、コードは行いません)。クエリは次のようになります。
select
price
from
price_history
where
product_id = myProductID
date <= myDate
order by date desc
limit 1;
ただし、このオプションには1つの利点があります:ギャップやオーバーラップを心配する必要はありません(以下を参照)。 しかし、時間を進めるために複数のレコードを再生してそれらを順次処理する必要があるため、期間を変更したい場合、大きな欠点があります。
そのため、クエリは次のように単純なので、2番目のオプションの方が優れています。
select
price
from
price_history
where
product_id = myProductID and
from_date <= myDate and
( thru_date >= MyDate or thru_date is null);
明らかに、実際の価格は、まだ有効期限がないため、THRU_DATE列にnullが含まれているはずです。
ただし、考慮すべき点がいくつかあります:
PRICE_HISTORY
テーブルのPKは(PRODUCT_ID,FROM_DATE)
である必要があります。または、PKを代理にする場合は、(PRODUCT_ID,FROM_DATE)
に一意のインデックスが必要です。THRU_DATE
にnullを含めることができるのは、製品ごとに1行のみです。トリガーまたはSP再度。ボトムライン:
一部の人はオプション1(1行に1つの日付)を好むため、ギャップや重複を気にする必要はありませんが、2番目のオプションはより人間が読みやすいIMOです。
いずれの場合も、価格監査テーブルを追加して、誰がいつどの行を変更したかを反映します。 old_priceとnew_priceだけでなく、from_dateとthru_dateの変更も登録する場合は、PRICE_HISTORY
テーブルのPKを代理にする必要があります。また、PRICE_HISTORY
とPRICE_AUDIT
を混同しないでください。 1つのテーブルには時間の経過に伴う製品の価格が含まれ、2番目のテーブルには前者のレコードに加えられた変更が保持されます。
AUDIT_TABLE
およびER図を含む、時間の経過に伴う価格の変化に関連する これらの他の回答 を参照してください。
ほとんどの人と同じように、オプション2を使用します。 FromDateとToDateの好ましい結果の1つは、ギャップを危険にさらすことなく、一時的な割引をエレガントに実装できることです。
Table Product_Price
Product_ID Price FromDate ToDate
---------- ----- -------- --------
1 300 1/1/1900 Null
1 250 1/1/2016 8/1/2016
次に、関心のある日に有効なlowest価格を取得して、選択を行う必要があります
一時的な高価格が必要な非常に奇妙な状況でない限り、その場合は複数の挿入を行う必要があります。
永続的な価格変更は、終了日を含む古い価格の更新と新しい価格の挿入を使用して実装されます。
私の意見では、代わりに別のテーブルをItem_Pricingとして作成する必要があります。これは、価格設定履歴を確定するのに役立ちます。テーブルのItem_Pricing履歴は、このItem_Pricing(id [PK]、itm_id [FK]、price、price_still_in_use、date_price_created、...)のようになります。アイデアは、カラムprice_still_in_useは、値1(yes)または0(no)を持つことができるフラグと見なす必要があります。次に、テーブルでtransactionこれは考慮すべき価格です。次に、各トランザクションまたは販売は、引き続き使用されている価格設定に関連している必要があります。
トランザクション(id [PK]、...、item_pricing_id [FK] //これは、Item_Pricing(item_pricing_id)を指します、数量、日付)
したがって、アプリケーションでアイテムの価格が変更された場合、そのアイテムの価格は、使用されていなければ使用できなくなります。トリガーはまた、最良の結果を得るのに役立つ可能性があります。そのため、同じアイテムが、列(属性)price_still_in_useの値がyesである価格を複数持つことはできません。