2011-05-25 132 views
2

數據庫關係週期聞起來像不好的數據庫設計。下面是我認爲它不能防止這種情形:數據庫關係週期

  • 一個公司位置(市)
  • 一個公司產品(巨無霸)

  • 商品現有店鋪地址(沙特阿拉伯No Bacon Burger)

目前的設計將允許您提供產品屬於這個公司位置屬於這個公司

公司
1 - 麥當勞
2 - 漢堡王

位置
1 - 紐約,建設1 - 麥當勞(1)
2 - 阿姆斯特丹,建設2 - 漢堡王(2)

產品
1 - Big M AC - 麥當勞(1)

產品展示您
1 - 巨無霸(1) - 阿姆斯特丹,2棟​​(2)

麥當勞銷售的巨無霸,漢堡王沒有,但似乎他們的建築確實:)
當我們添加關係到產品這也是位置依賴關係變得更糟。

我該怎麼做才能防止週期?
如何確保數據庫數據的完整性?

+1

「當我們向產品添加也是位置依賴的關係時,情況會變得更糟。如果他們也是公司依賴的話,那將更加棘手。 XYZ Burgers可能會賄賂一名沙特阿拉伯官員並有權在旅遊景點銷售BLT。 :-) – 2011-05-25 10:12:17

回答

2

如果我們開始與LocationCompanyProduct作爲獨立的實體 - 我想你想:

enter image description here

create table ProductAtLocation (
     CompanyID integer 
    , LocationID integer 
    , ProductID integer 
); 

alter table ProductAtLocation 
    add constraint pk_ProdLoc primary key (CompanyID, LocationID, ProductID) 
    , add constraint fk1_ProdLoc foreign key (CompanyID, LocationID) references CompanyLocation (CompanyID, LocationID) 
    , add constraint fk2_ProdLoc foreign key (CompanyID, ProductID) references CompanyProduct (CompanyID, ProductID) 
; 

而且如果Product是依賴實體(取決於在公司):

enter image description here

+0

從技術上講,您正在爲我的問題提供解決方案因此我已經將答案標記爲答案。從實際的角度來看,我選擇在我的db設計中保留循環(如dportas所示,循環不一定是壞的)。謝謝! – Zyphrax 2011-05-25 15:23:20

0

我不同意 - 這個說法是不正確:

目前的設計將讓你 提供的產品不屬於本 公司

如果產品不屬於對公司來說,那麼它就不會有該公司的外鍵。一個公司可能有許多產品,但一個產品只能屬於一個公司。這是一對多的關係。

至於產品 - 位置,這聽起來像是一個多對多的關係:產品可以在多個位置提供,而位置可以銷售許多產品。您需要一個Product_Location JOIN表。

更新:

您添加的記錄只能說明問題。位置不僅僅是一座建築;麥當勞和漢堡王可能在同一棟大樓內,但他們不在該大樓的同一地點。您的位置表格除街道地址外還需要額外的列。我的意見仍然存在。漢堡王將無法賣出一臺巨無霸,如果你正確地設計這個。你還沒有對;因此你的困惑。

+0

我已經添加了一些數據庫記錄來澄清問題。 – Zyphrax 2011-05-25 10:17:56

+0

「1號樓」描述了銷售發生的地點(詳細程度無關緊要)。位置表中的其他列不會添加數據庫完整性。 – Zyphrax 2011-05-25 12:29:30

4

循環依賴並不是自動「糟糕的數據庫設計」。從概念模型的角度來看,如果這樣的依賴關係準確地表示你正在嘗試建模的東西,那麼它就不是「錯誤的」。

不幸的是,SQL的限制常常使得強制或不可能實施循環的約束。在SQL中,通常必須通過以某種方式打破約束或通過在過程代碼中實現規則而不是通過數據庫約束來妥協。

2

你真正需要什麼作爲SQL「斷言」。不幸的是,目前的DBMS不支持這些。斷言會是這樣的:

assertion product_location_check 
check (not exists (select null 
        from company_product_location cpl 
        where not exists 
        (select null 
        from company_products cp 
        join company_locations cl on c1.company_id = cp.company_id 
        and cp.product_id = cpl.product_id 
        and cl.location_id = cpl.location_id 
        and cp.company_id = cpl.company_id 
        ) 
       ) 
    ); 

在沒有這些,另一種可能性是設置鍵,使得規則可以檢查:

create table company_products 
(company_id references companies 
, product_id ... 
, primary key (company_id, product_id) 
); 

create table company_locations 
(company_id references companies 
, location_id ... 
, primary key (company_id, location_id) 
); 

create table company_product_locations 
(company_id ... 
, product_id ... 
, location_id ... 
, primary key (company_id, product_id, location_id) 
, foreign key (company_id, product_id) references company_products) 
, foreign key (company_id, location_id) references company_locations) 
); 

這確保了每個company_product_locations引用產品以及與同一公司相關的位置。

複雜約束的另一種可能性是使用物化視圖。我在Oracle here的背景下對此進行了博客。

+0

+1。任何想了解「如何執行復雜約束」(SQL ASSERTIONs)的人都應該(尤其是)閱讀「數據庫專業人士應用數學」,第11章。 – 2011-05-25 12:40:25

0

問題的部分原因是麥當勞和漢堡王都出售名爲「漢堡包」和「芝士漢堡」的產品和(我認爲)「雙層芝士漢堡」。因此,您在ProductLocation中存儲的信息不完整。

Product 
-- 
Big Mac McDonald's 
Hamburger McDonald's 
Hamburger Burger King 

ProductLocation 
Big Mac McDonald's New York, building 1 
Hamburger McDonald's New York, building 1 
Hamburger Burger King Amsterdam, building 2 

當他說「一個位置不僅僅是一棟建築物」時,duffymo說得對。

以下是實現這些約束的一種方法。我放棄了身份證號碼,因爲他們傾向於隱藏實際發生的事情。

create table company (
    co_name varchar(15) primary key 
); 

insert into company values 
('McDonald''s'), 
('Burger King'); 

create table location (
    loc_name varchar(30) primary key, 
    co_name varchar(15) not null references company (co_name), 
    unique (loc_name, co_name) 
); 

insert into location values 
('New York, building 1', 'McDonald''s'), 
('Amsterdam, building 2', 'Burger King'); 

create table product (
    co_name varchar(15) not null references company (co_name), 
    product_name varchar(15) not null, 
    primary key (co_name, product_name) 
); 

insert into product values 
('McDonald''s', 'Big Mac'), 
('McDonald''s', 'Hamburger'), 
('McDonald''s', 'Cheeseburger'), 
('Burger King', 'Hamburger'), 
('Burger King', 'Cheeseburger'); 

create table product_location (
    loc_name varchar(30) not null references location (loc_name), 
    co_name varchar(15) not null, 
    product_name varchar(15) not null, 
    foreign key (co_name, product_name) references product (co_name, product_name), 
    foreign key (loc_name, co_name) references location (loc_name, co_name), 
    primary key (loc_name, co_name, product_name) 
); 

insert into product_location values 
('Amsterdam, building 2', 'Burger King', 'Cheeseburger'); 

注意product_location中的重疊外鍵。重疊外鍵保證公司確定的位置和產品所屬的公司是同一家公司。現在下面的INSERT將會失敗並且違反外鍵約束。

insert into product_location values 
('Amsterdam, building 2', 'McDonald''s', 'Cheeseburger');