2

小売業者のデータ モデルを理解しようとしています。

この小売業者は全国に複数の店舗を持ち、次の階層を使用してモデル化されています。

Channel -> Zone -> City -> Store

各ストアには複数の記事が含まれています。そして、各記事には次のような属性があります

  • アクティベーション フラグ (記事の存在を示します)
  • 価格
  • サプライヤー
  • 倉庫

現在、小売業者はこれらの属性を階層の任意のレベルで設定できます。次のケースを考慮してください。

  • チャネル レベルで記事の価格を設定すると、すべてのストアに適用されます。
  • より高いレベルで設定された価格は、他のレベルで上書きできます。たとえば、都市内の店舗のみ、または特定の店舗の都市レベルで。
  • これは、上記のすべての属性に適用されます。

現時点では、階層の最上位でグローバル ルールを定義し、個々の行として個別に例外を呼び出すことにより、RDBMS を使用してモデル化しています。たとえば、価格表では、チャネル レベルで記事の価格が設定され、任意のレベルでの変更は個別に指定されます。明らかに、ストア レベルで属性をフェッチする場合、これはあまり効率的ではありません。

サンプルデータ

Channel、Zone、City、および Store をまとめてエンティティと呼ぶとします。チャネルの ID は >= 4000、ゾーン >= 3000、シティ >= 2000 で、ストアの範囲は 0 から 1000 です。

階層関係データのサブセットを以下に示します。

Channel   | Zone     | City    | Store |
----------+----------+------------------
4001      | 3001     | 2001    | 13    |
4001      | 3001     | 2001    | 14    |
4001      | 3001     | 2002    | 15    |
4001      | 3002     | 2003    | 16    |
4001      | 3003     | 2006    | 74    |

価格表

ArticleID | EntityID | Price
----------+----------+----------
12345     | 4001     | 2.5
12345     | 2003     | 2.9
12345     | 74       | 3.0

ここでは、チャネル 4001 の価格 2.5 がすべてのストアの記事に設定されます。次の 2 行は、一部の店舗で価格の例外を設定します。都市 2003 に設定された 2 番目の価格 2.9 は、上記の階層関係に従って、店舗 16 の商品にのみ適用されます。3 行目は、店舗 74 の商品の価格 3.0 を直接設定します。

これにより、現在のモデルのアイデアが得られることを願っています。それで、これを保存するためのより良い方法を提案できますか?

4

1 に答える 1

2

リレーショナル モデルでツリーと階層を表す方法はほとんどありません。SO で検索すると、かなりの数の回答が返されます。

このモデルの主なアイデアは、クロージャ テーブルと階層レベルで階層を表すことです。したがって、レベルテーブルには(1, Channel) , (2, Zone) , (3, City) , (4, Store).

クロージャ テーブルは、各ノードとそのノードのすべての子孫を公開します。各ノードも独自の子孫であることに注意することが重要です。

ここに画像の説明を入力

最初の CTE クエリ (q_00) は、ノードの価格を選択し、それをすべての子孫に割り当てます。LevelDiff列は、価格指定ノードである子孫ノードからのレベル数を計算します

価格は複数のレベルで指定される可能性があるため、最後のクエリでは、LevelDiffが最小のレベルで指定された店舗価格が選択されます。

構文は ですがPostgeSQL、他のものにも簡単に変換できるはずです。

with q_00 as (
    select
          a.ProductID
        , c.LocationID
        , c.LocationLevel
        , a.Price
        , t.DescendantLocationID
        , t.DescendantLevel
        , (t.DescendantLevel - c.LocationLevel ) as LevelDiff
    from ProductPrice as a
    join Product      as b on b.ProductId  = a.ProductID
    join Location     as c on c.LocationID = a.LocationID
    join TreeClosure  as t on t.LocationID = c.LocationID
)
select
      a.ProductID
    , DescendantLocationID
    , Price
from q_00  as a
join Level as w on w.LevelNo = a.DescendantLevel
where w.LevelName = 'Store'
  and a.Leveldiff = (select min(LevelDiff)
                       from q_00 as x 
                       where x.DescendantLocationID = a.DescendantLocationID 
                         and x.ProductID = a.ProductID )    ;

要約すると、これがテスト結果です。価格は次のように定義されました。

Channel=1,                        Product=1, Price = 11.0
Channel=1, City=111,              Product=1, Price = 11.5
Channel=1, City=111, Store =1112, Product=1, Price = 12.0

クエリが返されます (以下のテスト データを参照)

ProductID | DescendantLocationID | PriceID
-----------------------------------------
    1         1231                  11.00
    1         1232                  11.00
    1         1111                  11.50
    1         1112                  12.00

これがDDL(PosgreSQL)です

CREATE TABLE Level ( 
    LevelNo              integer      NOT NULL ,
    LevelName            varchar(20)  NOT NULL 
);
ALTER TABLE Level ADD CONSTRAINT XPKLevel PRIMARY KEY (LevelNo) ;


CREATE TABLE Location ( 
    LocationID           integer  NOT NULL ,
    LocationLevel        integer  NOT NULL 
);
ALTER TABLE Location ADD CONSTRAINT XPKLocation  PRIMARY KEY (LocationID);
ALTER TABLE Location ADD CONSTRAINT XAK1Location UNIQUE      (LocationID, LocationLevel) ;


CREATE TABLE Product ( 
    ProductID            integer  NOT NULL 
);
ALTER TABLE Product ADD CONSTRAINT XPKProduct PRIMARY KEY (ProductID);


CREATE TABLE ProductPrice ( 
    ProductID            integer        NOT NULL ,
    LocationID           integer        NOT NULL ,
    Price                decimal(19,2)  NOT NULL 
);
ALTER TABLE ProductPrice ADD CONSTRAINT XPKProductPrice PRIMARY KEY (ProductID, LocationID);

CREATE TABLE ProductSupplier ( 
    ProductID            integer  NOT NULL ,
    LocationID           integer  NOT NULL ,
    SupplierID           integer  NOT NULL 
);
ALTER TABLE ProductSupplier ADD CONSTRAINT XPKProductSupplier PRIMARY KEY (ProductID, LocationID);


CREATE TABLE Supplier ( 
    SupplierID           integer  NOT NULL 
);
ALTER TABLE Supplier ADD CONSTRAINT XPKSupplier PRIMARY KEY (SupplierID) ;

CREATE TABLE TreeClosure ( 
    LocationID           integer  NOT NULL ,
    DescendantLocationID integer  NOT NULL ,
    DescendantLevel      integer  NOT NULL 
);
ALTER TABLE TreeClosure ADD CONSTRAINT XPKTreeClosure PRIMARY KEY (LocationID, DescendantLocationID);


ALTER TABLE Location
    ADD CONSTRAINT FK1_Location FOREIGN KEY (LocationLevel) REFERENCES Level(LevelNo);


ALTER TABLE ProductPrice
    ADD CONSTRAINT FK1_ProductPrice FOREIGN KEY (ProductID) REFERENCES Product(ProductID);


ALTER TABLE ProductPrice
    ADD CONSTRAINT FK2_ProductPrice FOREIGN KEY (LocationID) REFERENCES Location(LocationID);


ALTER TABLE ProductSupplier
    ADD CONSTRAINT FK1_PrdSup FOREIGN KEY (ProductID) REFERENCES Product(ProductID);

ALTER TABLE ProductSupplier
    ADD CONSTRAINT FK2_PrdSup FOREIGN KEY (SupplierID) REFERENCES Supplier(SupplierID);


ALTER TABLE ProductSupplier
    ADD CONSTRAINT FK3_PrdSup FOREIGN KEY (LocationID) REFERENCES Location(LocationID);


ALTER TABLE TreeClosure
    ADD CONSTRAINT FK1_TC FOREIGN KEY (LocationID) REFERENCES Location(LocationID);

ALTER TABLE TreeClosure
    ADD CONSTRAINT FK2_TC FOREIGN KEY (DescendantLocationID,DescendantLevel) REFERENCES Location(LocationID,LocationLevel);

そして、テストするいくつかのデータ

insert into Level (LevelNo, LevelName)
values
  (1, 'Channel') 
, (2, 'Zone') 
, (3, 'City') 
, (4, 'Store')
;

insert into Product (ProductID)
values  (1) , (2) , (3) 
;

-- Locations
insert into Location (LocationID, LocationLevel)
values
  (1,    1) 
, (11,   2)
, (111,  3)
, (1111, 4)     
, (1112, 4)
, (12,   2)
, (123,  3)
, (1231, 4) 
, (1232, 4)     
;

-- Tree closure (hierarchy)

insert into TreeClosure (LocationID, DescendantLocationID, DescendantLevel)
values
  (1   , 1   , 1)
, (1   , 11  , 2)
, (1   , 111 , 3)
, (1   , 1111, 4)
, (1   , 1112, 4)
, (11  , 11  , 2)
, (11  , 111 , 3)
, (11  , 1111, 4)   
, (11  , 1112, 4)
, (111 , 111 , 3)
, (111 , 1111, 4)   
, (111 , 1112, 4)
, (1111, 1111, 4) 
, (1112, 1112, 4)

--  

, (1   , 12  , 2)
, (1   , 123 , 3)
, (1   , 1231, 4) 
, (1   , 1232, 4)
, (12  , 12  , 2)
, (12  , 123 , 3)
, (12  , 1231, 4) 
, (12  , 1232, 4)
, (123 , 123,  3)
, (123 , 1231, 4) 
, (123 , 1232, 4)   
, (1231, 1231, 4) 
, (1232, 1232, 4)
;

--  pricing
insert into ProductPrice (ProductID, LocationID, Price) values (1, 1   , 11.0);
insert into ProductPrice (ProductID, LocationID, Price) values (1, 111 , 11.5);
insert into ProductPrice (ProductID, LocationID, Price) values (1, 1112, 12.0);
于 2012-11-17T23:49:18.577 に答える