我将用一个例子解释我的案例。
我有以下表格:persons
,places
,pictures
。人和地都有很多照片。在保持参照完整性的同时,在数据库方案中表达这一点的最佳方法是什么?
persons
和pictures
以及places
和pictures
之间创建关联表。但是外键会在关联表中,我不能强制删除地图等时删除的图片。目前我倾向于第二种方法,但我不喜欢它。
答案 0 :(得分:2)
没有任何一种尺寸适合所有解决方案,可以打勾你想要的所有方框。但我以前见过的是
3)为将共享关系的项目引入基表:
CREATE TABLE Entities (
EntityID int not null primary key,
EntityType varchar(10) not null,
constraint CK_EntityTypes CHECK (EntityType in ('Person','Place')),
constraint UQ_Entities_WithTypes UNIQUE (EntityID,EntityType)
)
然后构建您的People
和Places
表:
CREATE TABLE People (
PersonID int not null PRIMARY KEY,
EntityType AS CAST('Person' as varchar(10)) persisted,
...Other columns...
constraint FK_People_Entities FOREIGN KEY (PersonID,EntityType) references Entities (EntityID,EntityType)
)
CREATE TABLE Places (
PlaceID int not null PRIMARY KEY,
EntityType AS CAST('Place' as varchar(10)) persisted,
...Other columns...
constraint FK_Places_Entities FOREIGN KEY (PlaceID,EntityType) references Entities (EntityID,EntityType)
)
(我不确定Entities
在考虑地方时是完全正确的 - 一个更好的名字可能会向你暗示。)
然后,您可以Pictures
引用EntityID
。
否则,如果我必须在1和1之间选择2,我通常建议1.除非涉及的“类型”数量变大,否则它仍然不会使Pictures
表太宽,正如您所观察到的,您至少可以使用正常如有必要,FK机制可以强制执行级联。
4)如果Pictures
目前只是一张非常裸的表,可能会查询是否应该有一个图片表,或者每个类型一个。人们的照片和地方的图片经常会一起查询(即使它们是,基于UNION ALL
的查询是否可以隐藏您使用单独表格的事实?)
答案 1 :(得分:1)
我认为有三种方法。一种是将每个实体映射到图片的单独表格。类似的东西:
create table PersonPictures . . .
PersonId int not null,
PictureId int not null
. . .
create table PlacesPictures . . .
PlaceId int not null,
PictureId int not null
当人物和地方是独立的实体并且可能有关于图片的其他信息时,这种情况有所不同(说明该人穿着的地方或地点的观点)。
如果人物和地方真的只是图片的属性,那么你可以拥有:
create table AttributesPictures . . .
PictureId int not null,
AttributeType varchar(255), -- 'Person', 'Place'
PersonId int,
PlaceId int
在这种情况下,您可以设置约束以确保AttributeType
仅采用明确定义的值(或使用带有单独查找表的AttributeId)。对外键的约束:当AttributeType ='Person'时,PersonId不为null,Place Id为null。
如果一张图片最多只有一个人和一个地方,那么你可以将这些ID存储在图片记录本身中 - 这种特殊情况下非常方便。
您采取的哪种方法应该更多地受到应用程序要求的驱动。在任何方法中,您都可以使用外键关系和级联删除来确保记录被删除。或者,您也可以使用触发器来强制执行关系完整性(尽管这不是我最喜欢的解决方案)。