【问题标题】:Referential integrity with multiple one to many associations具有多个一对多关联的参照完整性
【发布时间】:2013-01-28 22:39:25
【问题描述】:

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

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

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

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

【问题讨论】:

  • 您应该能够将 pic_id 添加到人物和地点。然后,创建触发器或级联规则以强制执行完整性。您可以扩展业务案例吗?是删除图片中的行,然后删除与这些图片关联的其他表中的行,还是删除人物和地点中的行,然后需要清理图片表?

标签: sql database referential-integrity


【解决方案1】:

没有一种万能的解决方案可以满足您的所有需求。但是我以前见过的一个是

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

【讨论】:

  • 我想,我现在会选择#1。
  • @PhoneixS - 1 和 2 在问题中。这个问题本质上是问“在这些之间进行选择”,但我想提出更多的选择。因此,您需要一起阅读问题和答案,以使编号有意义。
【解决方案2】:

我认为有三种方式。一种是使用单独的表格将每个实体映射到图片。比如:

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存储在图片记录本身中——在这种特殊情况下非常方便。

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

【讨论】:

    猜你喜欢
    • 2017-05-27
    • 2012-04-17
    • 1970-01-01
    • 1970-01-01
    • 2011-03-24
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-09-17
    相关资源
    最近更新 更多