特定の日付で製品価格のデータベースを照会できるように、製品価格の変化を追跡する必要があります。この情報は、履歴監査を計算するシステムで使用されるため、購入日に基づいて、正しい製品の正しい価格を返す必要があります。
私はデータベースの構築にpostgresを使用したいと思います。
データベースの設計が必要ですが、あらゆるベストプラクティスの提案も歓迎します。
特定の日付で製品価格のデータベースを照会できるように、製品価格の変化を追跡する必要があります。この情報は、履歴監査を計算するシステムで使用されるため、購入日に基づいて、正しい製品の正しい価格を返す必要があります。
私はデータベースの構築にpostgresを使用したいと思います。
データベースの設計が必要ですが、あらゆるベストプラクティスの提案も歓迎します。
回答:
シナリオを適切に理解している場合は、価格の時系列を保持するテーブルを定義する必要があります。したがって、私は同意します。これは、使用しているデータベースの一時的な側面に大きく関係しています。
状況を概念レベルから分析してみましょう。したがって、もしあなたのビジネスドメインで
それはつまり
IDEF1Xを示す図図1高度に簡略化されているがは、そのようなシナリオを示しています。
また、次のSQL-DDL論理レベル設計は、上記のIDEF1Xダイアグラムに基づいており、独自の正確なニーズに適応できる実現可能なアプローチを示しています。
-- At the physical level, you should define a convenient
-- indexing strategy based on the data manipulation tendencies
-- so that you can supply an optimal execution speed of the
-- queries declared at the logical level; thus, some testing
-- sessions with considerable data load should be carried out.
CREATE TABLE Product (
ProductNumber INT NOT NULL,
Etcetera CHAR(30) NOT NULL,
--
CONSTRAINT Product_PK PRIMARY KEY (ProductNumber)
);
CREATE TABLE Price (
ProductNumber INT NOT NULL,
StartDate DATE NOT NULL,
Amount INT NOT NULL, -- Retains the amount in cents, but there are other options regarding the type of use.
--
CONSTRAINT Price_PK PRIMARY KEY (ProductNumber, StartDate),
CONSTRAINT Price_to_Product_FK FOREIGN KEY (ProductNumber)
REFERENCES Product (ProductNumber),
CONSTRAINT AmountIsValid_CK CHECK (Amount >= 0)
);
Price
テーブルには、複合PRIMARY KEYは、2列、すなわちから成っていますProductNumber
(を参照するFOREIGN KEYとして、順番に、制約Product.ProductNumber
)とStartDate
(特に指摘日付特定した製品は、特定の時に購入した価格) 。
製品が同じ日に異なる価格で購入された場合、列の代わりに、特定の製品が正確な価格で購入されたときにインスタントを保持するラベルが付いたものを含めることができます。次に、PRIMARY KEYをとして宣言する必要があります。StartDate
StartDateTime
(ProductNumber, StartDateTime)
示されているように、データを直接操作するSELECT、INSERT、UPDATE、およびDELETE操作を宣言できるため、前述のテーブルは通常のテーブルです。したがって、(a)追加コンポーネントのインストールを回避でき、(b)すべてで使用できます。必要に応じて、いくつかの調整を加えた主要なSQLプラットフォーム。
有用と思われるいくつかの操作操作を例示するために、テーブルProduct
とPrice
テーブルにそれぞれ次のデータを挿入したとします。
INSERT INTO Product
(ProductNumber, Etcetera)
VALUES
(1750, 'Price time series sample');
INSERT INTO Price
(ProductNumber, StartDate, Amount)
VALUES
(1750, '20170601', 1000),
(1750, '20170603', 3000),
(1750, '20170605', 4000),
(1750, '20170607', 3000);
以来Price.EndDate
導出データ点があり、その後、あなたはそれを経由して取得するためにしなければならず、正確には、派生として作成することができ、テーブルビューの下に例示されるような「フル」の時系列を生成するために:
CREATE VIEW PriceWithEndDate AS
SELECT P.ProductNumber,
P.Etcetera AS ProductEtcetera,
PR.Amount AS PriceAmount,
PR.StartDate,
(
SELECT MIN(StartDate)
FROM Price InnerPR
WHERE P.ProductNumber = InnerPR.ProductNumber
AND InnerPR.StartDate > PR.StartDate
) AS EndDate
FROM Product P
JOIN Price PR
ON P.ProductNumber = PR.ProductNumber;
次に、そのビューから直接SELECTする次の操作
SELECT ProductNumber,
ProductEtcetera,
PriceAmount,
StartDate,
EndDate
FROM PriceWithEndDate
ORDER BY StartDate DESC;
次の結果セットを提供します:
ProductNumber ProductEtcetera PriceAmount StartDate EndDate
------------- ------------------ ----------- ---------- ----------
1750 Price time series… 4000 2017-06-07 NULL -- (*)
1750 Price time series… 3000 2017-06-05 2017-06-07
1750 Price time series… 2000 2017-06-03 2017-06-05
1750 Price time series… 1000 2017-06-01 2017-06-03
-- (*) A ‘sentinel’ value would be useful to avoid the NULL marks.
今、私たちはあなたが全体得ることに興味を持っていると仮定しましょうPrice
ためのデータProduct
で、主に識別をProductNumber
1750年にDate
2017年6月2日。ことを見Price
アサーション(又は行)が全体の中の電流または有効である区間(I)のから実行されることStartDate
に(II)のEndDate
、このDML操作
SELECT ProductNumber,
ProductEtcetera,
PriceAmount,
StartDate,
EndDate
FROM PriceWithEndDate
WHERE ProductNumber = 1750 -- (1)
AND StartDate <= '20170602' -- (2)
AND EndDate >= '20170602'; -- (3)
-- (1), (2) and (3): You can supply parameters in place of fixed values to make the query more versatile.
次の結果セットを生成します
ProductNumber ProductEtcetera PriceAmount StartDate EndDate
------------- ------------------ ----------- ---------- ----------
1750 Price time series… 1000 2017-06-01 2017-06-03
上記の要件に対処します。
示されているように、PriceWithEndDate
ビューは、ほとんどの派生データを取得する上で最も重要な役割を果たし、かなり通常の方法でFROMから選択できます。
使用しているプラットフォームがPostgreSQLであることを考慮に入れて、公式ドキュメントサイトのこのコンテンツには、「マテリアライズド」ビューに関する情報が含まれています。他のSQLデータベース管理システム(DBMS)は、非常によく似た物理的な手段を提供しますが、Microsoft SQL Serverの「インデックス付き」ビューなど、異なる用語が適用される場合があります。
あなたは、アクションで議論DDLとDMLコードサンプルを見ることができます。このデシベル<>フィドルとで、このSQLフィドル。
ではこのQ&A私たちはの変更が含まビジネスコンテキスト話し合う製品価格をあなたが興味のそれを見つけることができて、より多くのextenseスコープを持っています。
これらのスタックオーバーフローのポストが保持している列の種類に関する非常に関連ポイントカバー通貨のPostgreSQL内のデータを。
これは私が行った作業に似ていますが、価格(この場合)に開始日列と終了日列があるテーブルを使用する方がはるかに便利/効率的であることがわかったので、targetdateを持つ行を探しているだけです。 > = startdateおよびtargetdate <= enddate。もちろん、データがこれらのフィールド(実際の終了日が存在しないNullではなく、9999年12月31日の終了日を含む)と共に格納されていない場合、データを生成するための作業を行う必要があります。実際には、デフォルトで終了日=今日の日付として毎日実行しました。また、私の説明には、終了日1 =開始日2-1日が必要です。– @Robert Carnegie、2017年6月22日20:56:01Z
方法私はアドレスの上に特性の事業ドメインを提案前述の結果として、宣言についてのご提案を適用し、EndDate
「フィールド」とは異なり-which列として-という名前のベーステーブルのをPrice
暗示するデータベースの論理構造があろうと概念スキーマを正しく反映していない。概念スキーマは、(1)基本情報と(2)導出可能な情報の区別を含め、正確に定義および反映する必要がある。
それとは別に、そのような一連のアクションは重複を導入します。これはEndDate
、(a)導出可能なテーブルと(b)という名前のベーステーブルPrice
により、重複したEndDate
列を使用してを取得できるためです。これは可能性のあることですが、開業医が上記のアプローチに従うことを決定した場合、開業医はデータベースのユーザーにそれが伴う不便さと非効率性について明確に警告する必要があります。これらの不便さや非効率性の1つは、たとえば、各値が手元の値のすぐ次の行の列の値と常にPrice.EndDate
等しいことを常に保証するメカニズムを開発する緊急の必要性です。Price.StartDate
Price.ProductNumber
対照的に、私が提起した問題の派生データを生成する作業は、正直なところ、まったく特別ではなく、(i)データベースの抽象化の論理レベルと概念レベルの間の正しい対応を保証する必要があり、(ii )データの整合性を確保します。前述のように、どちらの側面も明らかに非常に重要です。
あなたが話している効率性の側面が一部のデータ操作操作の実行速度に関連している場合、それは適切な場所、つまり物理レベルで、たとえば(1 )特定のクエリ傾向、および(2)使用するDBMSによって提供される特定の物理メカニズム。それ以外の場合、適切な概念論理マッピングを犠牲にして、関連するデータの整合性を損なうと、簡単に堅牢なシステム(つまり、貴重な組織資産)が信頼できないリソースに変わります。
不連続または分離した時系列
一方、EndDate
時系列テーブルの各行のを保持する方が便利で効率的であるだけでなく、要求される場合もありますが、それはもちろんビジネス環境固有の要件に完全に依存します。そのような状況の一例は、
このシナリオは、図2に表示されているIDEF1Xダイアグラムで表しています。
その場合、はい、仮想Price
テーブルは次のような方法で宣言する必要があります。
CREATE TABLE Price (
ProductNumber INT NOT NULL,
StartDate DATE NOT NULL,
EndDate DATE NOT NULL,
Amount INT NOT NULL,
--
CONSTRAINT Price_PK PRIMARY KEY (ProductNumber, StartDate, EndDate),
CONSTRAINT Price_to_Product_FK FOREIGN KEY (ProductNumber)
REFERENCES Product (ProductNumber),
CONSTRAINT DatesOrder_CK CHECK (EndDate >= StartDate)
);
そして、はい、その論理DDL設計により、物理レベルでの管理が簡略化EndDate
されます。これは、比較的簡単な構成で列(図に示されているように、ベーステーブルで宣言されている)を含むインデックス作成戦略を立てることができるためです。
次に、以下のようなSELECT操作
SELECT P.ProductNumber,
P.Etcetera,
PR.Amount,
PR.StartDate,
PR.EndDate
FROM Price PR
JOIN Product P
WHERE P.ProductNumber = 1750
AND StartDate <= '20170602'
AND EndDate >= '20170602';
2017年6月2日に1750年までに主に特定されたPrice
データ全体を導出するために使用できます。Product
ProductNumber
Date
Temporal Tablesを見たいと思うでしょう。これらは、あなたが探しているものを正確に実行する機能を提供し、適切な拡張子を持つPostgresで利用できます。
このコンセプトは、さまざまなRDBMSプラットフォームで提供されているため、DBにとらわれないようにも見えます。
prices
持つテーブルprices_history
を作成します。Hibernate Enversはこれを自動化できます