数据建模:超类型/子类型

5

希望找到适当的建模方法来满足以下要求。

  1. 需要关注3种“方案”类型,即粉丝、乐队和乐队成员。
  2. 乐队成员将始终与一个乐队相关联,并且也可以是任何乐队的粉丝。
  3. 粉丝、乐队和乐队成员之间有共同点,但这3个实体也都有自己独特的属性。
  4. 粉丝可以成为任何乐队的粉丝或者不喜欢任何乐队。

这只是更大想法的一小部分,但它在扩展模型时产生了困惑。我认为它必须是第二个图表或其他选项,因为我不知道第一个模型中如何将乐队成员与乐队相关联。

感谢您的任何意见。

alt text

alt text

2个回答

12

注意事项

首先,需要注意一些限制条件。所有使用或存储的数据需要一起考虑/建模。例如,在“扩展模型中创建混乱”中,您已经发现了这一点。就我而言,由于不知道“Parties”(子类型)与其他实体的关系,使我无法提供完全正确的答案(这将不会改变)。
由于您提供的数据分为两部分,因此答案将分为两部分,并且第二部分将需要对第一模型进行更改。这不是抱怨,只是提前通知您,如果我事先看到所有数据,那么可以避免这种情况。
非常感谢您意识到需要对数据进行建模并遵循概念、逻辑和物理的科学(已记录了30多年)。这正是我所做的。您无法想象通过正式过程节省的时间和精力。
然而,在我的SO答案中并没有体现出来,因为那是一个“问题和答案”的网站,我必须回答提问者提出的问题。 (我回答问题比其他人更详细,即使如此,也会引起负面评论!)。请放心,我会按照正式顺序进行。
必须提到的是,关系建模是业界巨匠E F Codd博士和R Brown在1980年代的工作。该方法论基于他们的工作。IDEF1X在1993年成为NIST标准。当我回答数据建模问题时,我不是提供了一些我写书的个人方法,“我站在巨人的肩膀上”。
我遵循E F Codd博士的“关系模型”。
我拒绝Date;Darwen;Fagin等人的工作,因为它与“关系模型”相矛盾,是反关系的。
ERD(P Chen)是预关系、预IDEF1X且原始的比较。它没有概念的“标识符”,无法处理关系键。令人惊讶的是,ERD仍然被教授为“关系”,而IDEF1X则被压制。长达30年。

数据建模

  1. 是的,在这里使用超类型-子类型结构是正确的。不幸的是,这并不常见,因此不常被理解。
  • 子类型早在关系模型之前就存在,并且仍然存在。IDEF1X是关系数据建模的唯一标准,它有特定的符号。ERD没有。
  1. 即使实现了子类型,它们的实现方式也非常有限。子类型会改变超类型的角色。正确的实现非常罕见,我从未在任何地方看到过这种实现(除了我的客户的数据库实现和一些高端供应商)。

  2. 关键是,这可能看起来很“复杂”,但实际上它非常简单。

    这就是Ken Downs和Chris Behrens混淆建模简单性(高度可扩展)与未建模实现(不正确和不可扩展)的地方,因为他们采用了像Martin Fowler这样的小人物提出的简单方法。不冒犯,我明白人们会喜欢并捍卫他们所知道的东西,无论那有多么有限。

    • 请注意,每个子类型也是一个完全有效的实体(在物理上是一个表格,当我们到达那个阶段时),并且可以独立存在。

    • 对于具有与这些子类型相关系的较低级别或事务或功能表,技巧在于使用正确的子类型(角色)。常见的错误是使用Party,然后失去了子类型或角色的意义和正确的参照完整性。

    • 所有角色名称都是派生Party,但这并不是使用正确角色而不是Party的有效理由。

    • 在这里,您非常了解数据,但(没有人教过您这个),您混淆了角色和子类型。

    • BandMemberFan不是Parties。他们首先是Persons(而Person是一个Party

  3. 为了澄清这些观点,在这个概念层面上,我们需要使用实体和标识符(而不是属性),而不仅仅是实体。因此,我也提供了这一点。

    • 看起来你有ERwin(最好的!);它允许您非常方便地查看单个模型在那个层次。即使在这个抽象层面上,也要在实体中实现标识符。

障碍

在介绍模型之前,我想先指出这些问题,因为您似乎非常有兴趣学习 IDEF1X,这是建模关系数据库的标准方法,以便在将来简化您的模型。SO或任何网站都不是正式互动教育的好媒介,但我们会尽力而为。

  1. 在模型(1)中,Band不能是独立的(方形角):因为它被确定为依赖于Party;它是Party的子类型;并且它具有相同的标识符。

  2. 缺失的基数非常重要。将其放入实际上有助于解决模型问题。我不关心IDEF1X(圆圈)与IEEE(鸦脚)之间的区别,但我总是在建模过程中添加它们,并随着模型的进展不断更改它们。

    • 您的模型没有显示一个Band由多个成员组成。等等。

      虽然编程可以逐步进行(一旦定义稳定),但建模不行。例如,您不能对实体进行建模,而不对关系进行建模;关系而不是基数。这就是为什么它们是不同的科学,程序员不是好的建模者,反之亦然。
  3. 此时,规则也非常重要。事实上,建模就是建模规则。因此,纠正或调节规则是建模过程的一部分。

    • 粉丝可以是任何乐队的歌迷,也可以不是是不合理的。如果一个Person根本没有,那么他们是普通公众的成员,他们与任何Band都没有关系。一个普通的Person

    • Fan至少与一个Band有关系。事实上,与Band有关系是将Person从该领域中带出并导致存储Fan详细信息或特定的乐队粉丝详细信息。

    • 如果存在Fan with no Band这样的实体(即,您正在存储该实体的详细信息,与我的模型不同),请告知,我将更改模型(纸张很便宜!)。

  4. 动词短语在此阶段也很重要;不亚于我上面提到的规则和基数,它是建模过程的一部分,并且随着模型的进展需要改变/调节。您无法想象正确使用动词短语有多重要。将它们放入可能有助于您澄清子类型与角色的区别。以下是每个数据建模者都熟记于心的定义。

    • 实体是模型中的名词

    • 关系是动词,发生在名词之间的行动

    • 动词短语定义这些行动(这就是为什么它们被准确地称为动词短语,这不是一个有趣的名称)。

IDEF1X符号文件所述,对于关联表,通过它们的动词短语“through”读取到关联的另一侧的父级。

  • Person制作了一对多的Bands,因此是一个Member

  • Band由一对多的People组成,他们是Members

  • Person资助Band,这使他们成为Fan(不仅仅是在Fan表中拥有一行的Person

  • Band依赖于是FansPeople

想出最短、最有意义的动词短语;不要使用简单化的词汇(应避免使用“包括”),这对建模者来说是一个挑战。请随意改善我提供的动词短语。

这是你的Party Data Model在实体和键级别上的IDEF1X。

如果读者不熟悉关系数据库建模标准,可能会发现我的IDEF1X符号很有用。

注意

我所做的一切只是解决上述识别出来的子类型、角色和关系的基数。

  1. 当你评估第二批或交易实体时,子类型与角色的相关性将更加清晰(正如你所说,在这里我们只有标识实体)。

  2. 标识符。这值得详细说明,不仅是为了澄清模型,也因为它是使用IDEF1X标识符的一个很好的例子,以及它们所具有的强大功能。您已经在模型中指出了这一点(实线),我只是给予了全面的处理。

    • PersonBandParty的子类型。他们也是Party的角色。因此,从那一点开始,我们使用PersonIdBandId,而不是PartyId(尽管它是PartyId)。

    • Person扮演Member的角色时,我们使用MemberId(它是PersonId,它是PartyId)。

    • Person扮演Fan的角色时,我们使用FanId(它是PersonId,它是PartyId)。

假设您正在列出一个乐队的“粉丝”,您的查询以“粉丝”为中心。如果每个表上都有那些“ID”替代键,您将被迫连接“人员”,然后连接“派对”。但是由于您拥有关系标识符,因此可以直接转到“派对”:
SELECT  ...,
        Name  -- Party.Name
        ...
    FROM Party
    JOIN Fan
        ON PartyId = FanId

跳过中间的“Band”表。事实是,规范化关系数据库需要更少的连接、更少的资源(处理、缓存、磁盘I/O),这也是它们表现得更好的原因之一。这个神话没有科学依据。请评估并提出具体问题。
更新
有关子类型的通用处理和真正的SQL平台实现细节,请参阅我的Subtype Document

1
感谢您的回复。我是数据库新手,尝试按照标准学习,而不仅仅是将我的创造性思维引入到设计中。这只是我正在为自己进行的一个概念设计的一小部分,受到在Stack上发布的一些数据模型的启发,我想尝试通过更正式的流程来进行数据库设计。我理解您关于必须查看所有信息才能给出真正准确的答案的观点。(续) - swisscheese
1
我承认我很固执,因为我正在学习,我不想把我的整个图表与我知道存在的现有漏洞一起发布并寻求帮助。我不是在寻找有人只是拿走我的要求并为我设计东西,我想要自己理解。所以感谢您的回复,虽然您没有看到我在我的端上所做的事情,但我可以说您的回复已经帮了我很多,我将把所学到的知识应用到我的概念模型中。 - swisscheese
1
我对动词短语有些困惑,但在您的解释下,我不再有借口了,现在是时候去填写它们了。由于我相信我不是唯一可以从这个过程中受益的人,所以我会把我的工作记录在这个网站上供其他人查看。同时,回到工作中完善我的模型。 - swisscheese
2
  1. 两个切片。放心,我已经说过“没有抱怨,只是保留更改模型的权利”。
  2. 你的态度很好。我可以看出你正在努力学习方法论,这就是为什么我发布了每个要点的完整解释
  3. 我认为我的回答能够激发一些寻求者是一个严肃的赞美,哇!这本身就值得在这个网站上承受负面情绪。
  4. 请投票(这与选择答案不同),我会得到10美分。
- PerformanceDBA
3
@Air 我原本期望读者能够从上下文中明白这只是一个代码片段,而不是可运行的代码。尽管如此,我还是进行了更新。 - PerformanceDBA

1

我认为这比你想象的要简单。你有两个对象 - Band和Person,它们可以以两种不同的方式连接,即作为粉丝或成员。这是一个快速的数据库脚本,没有外键或其他任何东西:

CREATE TABLE [dbo].[XREFBandMembers](
    [MemberID] [int] NOT NULL,
    [BandId] [int] NOT NULL,
 CONSTRAINT [PK_XREFBandMembers] PRIMARY KEY CLUSTERED 
(
    [MemberID] ASC,
    [BandId] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

CREATE TABLE [dbo].[XREFBandFans](
    [FanId] [int] NOT NULL,
    [BandId] [int] NOT NULL,
 CONSTRAINT [PK_XREFBandFans] PRIMARY KEY CLUSTERED 
(
    [FanId] ASC,
    [BandId] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

CREATE TABLE [dbo].[People](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [Name] [nvarchar](100) NOT NULL,
 CONSTRAINT [PK_People] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]

CREATE TABLE [dbo].[Bands](
    [Id] [int] IDENTITY(1,1) NOT NULL,
    [Name] [nvarchar](50) NOT NULL,
 CONSTRAINT [PK_Bands] PRIMARY KEY CLUSTERED 
(
    [Id] ASC
)WITH (PAD_INDEX  = OFF, STATISTICS_NORECOMPUTE  = OFF, IGNORE_DUP_KEY = OFF, ALLOW_ROW_LOCKS  = ON, ALLOW_PAGE_LOCKS  = ON) ON [PRIMARY]
) ON [PRIMARY]
GO

关于特定关系属性,您可以将它们放在XREF表中,例如,FanClubMembershipNumber放在XREFBandFans中。

@Chris,我相信这比我想象的要简单,但是我刚开始学习数据库,并试图采取一种有条不紊的方法从A点到Z点。这只是一个概念性项目,我正在学习中。话虽如此,我想在实际构建数据库和编写脚本之前,将其从逻辑模型转化为物理模型,以验证我的逻辑是否正确并测试其有效性。(续) - swisscheese
我明白你的意思。我对我的模型提出的一个批评是它没有强制要求任何乐队都必须有成员。我是说,我想你可以这样做,但这真的没有意义。我猜你得在触发器之类的东西里面设置。但这至少可以让你开始了。 - Chris B. Behrens
也许这是正确的方法,仍然可以让我达到我发布的要求的最终目标,但我肯定还没有能力看得那么远...感谢您的帮助。 - swisscheese
1
@swisscheese。你说得完全正确。现在考虑表格和物理实现还为时过早。如果你没有正确理解概念,那么逻辑(扩展等)就会失败。因此,坚持下去,如果你想要一个能够支持未计划增长的强大模型;那么先从逻辑开始;等到逻辑完全呈现出来之后;再考虑物理实现。触发器也是不必要的。 - PerformanceDBA
2
@Ken。没错,数据库不是面向对象的。需要应用不同的科学方法。你不能将面向对象建模应用于数据库建模。Fowler和Ambler的“比你想象的简单”是完全错误的,而且有很多失败的例子可以证明这一点。只需看看所有在SO上的问题,面向对象的开发人员都在为此问题苦苦挣扎。将数据库建模工作交给具备数据库建模资格的人员,而不是交给Fowler这样的人。 - PerformanceDBA
显示剩余2条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接