2012-11-17 93 views
2

我想弄清零售商的數據模型。建模分層屬性

零售商在全國擁有多家賣場和他們使用以下層次結構模型:

Channel -> Zone -> City -> Store 

每個存儲包含多篇文章。而且每篇文章都有類似

  • 啓動標誌屬性(這表明物品的存在)
  • 價格
  • 供應商
  • 倉庫

現在,零售商可以將這些屬性在任何層次結構中的層次。考慮以下情況:

  • 設置通道級別文章的價格將應用於所有商店。
  • 設置在更高級別的價格可以在任何其他級別被覆蓋。例如,在城市級別只適用於城市或特定商店的商店。
  • 這適用於上面列出的所有屬性。

到目前爲止,他們已經通過在層次結構頂部定義全局規則並分別作爲單獨行調用異常來使用RDBMS對其進行建模。比如價格表,將爲渠道級別的文章設置價格,任何級別的更改都將單獨指定。顯然,在商店級別獲取屬性時效率不高。

樣本數據

假設通道,區,市和商店被統稱爲實體。信道將具有IDS測距> = 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。接下來的兩行在一些商店設置價格例外。根據上述等級關係,爲城市2003設置的第二價格2.9僅適用於商店16中的物品。第三排直接爲商店74中的商品設置價格3.0。

希望這給出了當前模型的概念。那麼,你能否建議一個更好的方法來存儲這個?

回答

2

在關係模型中表示樹和層次結構的方法很少 - 在SO上搜索將返回相當多的答案。

該模型的主要思想是用閉合表和層次結構表示層次結構。 所以,等級表有(1, Channel) , (2, Zone) , (3, City) , (4, Store)

閉包表暴露節點的每個節點和所有後代。重要的是要注意每個節點也是它自己的後裔。

enter image description here

第一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); 

and som e數據測試

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);