2011-05-25 64 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');