我将用一个例子来解释我的情况。
我有以下表格:persons, places, pictures. 人和地方都有很多图片。在保持参照完整性的同时,在数据库方案中表达这一点的最佳方式是什么?
- 我可以为每个可能的关联添加一个列,但是当还有其他有图片的东西时,这会创建很多空白字段。
persons我可以在andpictures和placesand之间创建关联表pictures。但是,外键将在关联表中,我不能强制在删除地点等时删除图片。
目前我倾向于第二种方法,但我不喜欢它。
我将用一个例子来解释我的情况。
我有以下表格:persons, places, pictures. 人和地方都有很多图片。在保持参照完整性的同时,在数据库方案中表达这一点的最佳方式是什么?
persons我可以在andpictures和placesand之间创建关联表pictures。但是,外键将在关联表中,我不能强制在删除地点等时删除图片。目前我倾向于第二种方法,但我不喜欢它。
没有一种万能的解决方案可以满足您的所有需求。但我以前见过的一个是
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 和 2 之间进行选择,我通常会推荐 1。除非涉及的“类型”数量变大,否则它仍然不会使Pictures表格太宽,正如您所观察到的,您可以如有必要,至少使用正常的 FK 机制来强制级联。
4)如果Pictures现在只是一个非常裸的表,也许查询是否应该有一个图片表,或者每个类型一个。人物图片和地点图片是否会经常一起查询(即使是,UNION ALL基于查询的查询是否会隐藏您使用单独表的事实)?
我认为有三种方式。一种是有单独的表格将每个实体映射到图片。就像是:
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 不为空且 Place Id 为空。
如果一张图片最多只有一个人和一个地方,那么您可以将这些 id 存储在图片记录本身中——在这种特殊情况下非常方便。
您采用哪种方法应该更多地受应用程序需求的驱动。在任何方法中,您都可以使用外键关系和级联删除来确保适当地删除记录。或者,您也可以使用触发器来强制执行关系完整性(尽管这不是我最喜欢的解决方案)。