Database design 数据库关系周期
数据库关系周期闻起来像糟糕的数据库设计。以下是我认为无法避免的情况:Database design 数据库关系周期,database-design,cycle,relationship,Database Design,Cycle,Relationship,数据库关系周期闻起来像糟糕的数据库设计。以下是我认为无法避免的情况: 公司有地点(城市) 公司有产品(巨无霸) 产品在不同地点都有/没有(沙特阿拉伯没有培根汉堡) 当前的设计允许您在不属于本公司的地点提供不属于本公司的产品 公司 1-麦当劳 2-汉堡王 位置 1-纽约1号楼-麦当劳(1) 2-阿姆斯特丹2号楼-汉堡王(2) 产品 1-巨无霸-麦当劳(1) 产品位置 1-巨无霸(1)-阿姆斯特丹2号楼(2) 麦当劳卖巨无霸,汉堡王不卖,但他们的大楼似乎卖:) 当我们向产品添加同样依赖于位置的关
- 公司有地点(城市)
- 公司有产品(巨无霸)
- 产品在不同地点都有/没有(沙特阿拉伯没有培根汉堡)
1-麦当劳
2-汉堡王 位置
1-纽约1号楼-麦当劳(1)
2-阿姆斯特丹2号楼-汉堡王(2) 产品
1-巨无霸-麦当劳(1) 产品位置
1-巨无霸(1)-阿姆斯特丹2号楼(2) 麦当劳卖巨无霸,汉堡王不卖,但他们的大楼似乎卖:)
当我们向产品添加同样依赖于位置的关系时,情况会变得更糟 我能做些什么来防止这种循环?
如何确保数据库数据的完整性?我不同意-这句话不正确: 当前的设计将允许您 提供不属于您的产品 本公司 如果一个产品不属于某个公司,那么它就没有该公司的外键。一个公司可能有许多产品,但一个产品只能属于一个公司。这是一对多的关系 至于产品定位,这听起来像是一种多对多的关系:一个产品可以在多个地点提供,而一个地点可以销售许多产品。您需要一个产品位置联接表 更新:
您添加的记录仅澄清了问题。一个地点不仅仅是一座建筑物;麦当劳和汉堡王可能在同一栋楼里,但他们不在同一栋楼里的同一个位置。除了街道地址之外,您的位置表还需要其他列。我的意见仍然有效。如果你设计得当,汉堡王将无法出售巨无霸。你还没有把它做好;因此,您会感到困惑。循环依赖项不会自动成为“糟糕的数据库设计”。从概念建模的角度来看,如果这种依赖关系准确地表示了您试图建模的内容,那么它就不是“错误的”
不幸的是,SQL的限制常常使强制执行循环约束变得困难或不可能。在SQL中,您通常必须以某种方式打破约束,或者在过程代码中实现规则,而不是通过数据库约束来妥协。您真正需要的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)
);
这确保了每个公司的产品位置都引用了一个产品和与同一公司关联的位置
复杂约束的另一种可能性是使用物化视图。我曾在Oracle的博客中提到过这一点。如果我们从
位置开始,将公司
和产品
作为独立实体--我认为您尝试过:
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)
;
如果产品
为从属实体(取决于公司):
问题的一部分在于,麦当劳和汉堡王都销售“汉堡包”、“奶酪汉堡”和(我认为)“双层奶酪汉堡”。因此,您存储在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
达菲莫说得对,“地点不仅仅是一座建筑。”
下面是实现这些约束的一种方法。我删除了身份证号码,因为它们往往隐藏了真正发生的事情
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_位置中重叠的外键。重叠的外键保证与位置标识的公司和与产品标识的公司是同一家公司。现在,以下插入将失败,并违反外键约束
insert into product_location values
('Amsterdam, building 2', 'McDonald''s', 'Cheeseburger');
“当我们在产品中添加依赖于位置的关系时,情况会变得更糟。”如果它们也依赖于公司,情况会更棘手。XYZ汉堡可以贿赂沙特官员,并有权在旅游胜地出售BLT.:-)我添加了一些数据库记录来澄清这个问题。“Building 1”描述了销售发生的位置(细节级别无关)。位置表中的其他列不会增加数据库完整性。+1。任何想进一步了解“如何实施复杂约束”(即SQL断言)的人,也应该(尤其是)阅读“数据库专业人士应用数学”第11章。从技术上讲,您提供了我问题的解决方案,因此我将您的答案标记为答案。从实用的角度来看,我选择在我的db设计中保留周期(如dportas所描述的,周期不一定是坏的)。非常感谢。