0

我将用一个例子来解释我的情况。

我有以下表格:persons, places, pictures. 人和地方都有很多图片。在保持参照完整性的同时,在数据库方案中表达这一点的最佳方式是什么?

  1. 我可以为每个可能的关联添加一个列,但是当还有其他有图片的东西时,这会创建很多空白字段。
  2. persons我可以在andpicturesplacesand之间创建关联表pictures。但是,外键将在关联表中,我不能强制在删除地点等时删除图片。

目前我倾向于第二种方法,但我不喜欢它。

4

2 回答 2

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)
)

然后建立你的PeoplePlaces表:

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基于查询的查询是否会隐藏您使用单独表的事实)?

于 2013-01-28T14:28:50.200 回答
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 不为空且 Place Id 为空。

如果一张图片最多只有一个人和一个地方,那么您可以将这些 id 存储在图片记录本身中——在这种特殊情况下非常方便。

您采用哪种方法应该更多地受应用程序需求的驱动。在任何方法中,您都可以使用外键关系和级联删除来确保适当地删除记录。或者,您也可以使用触发器来强制执行关系完整性(尽管这不是我最喜欢的解决方案)。

于 2013-01-28T14:20:26.223 回答