3

在每个关于实体关系图的教程中,我都读到不允许为关系指定固定的基数。只有对 ERD 的非正式评论才能澄清飞行员的数量exactly 2

因此,例如,每个航班恰好有 2 名飞行员在场的航班和飞行员之间的关系必须表示为:

<flight> 0..N <------> 1..N <pilot>

而不是

<flight> 0..N <------> 2 <pilot>

我的符号是0..N= optional, many; 1..N= 强制性,许多,1= 强制性,一个。

这个限制是通用的吗?背后的原因是什么?

编辑:澄清了我的符号。

编辑:我可以看到两个关系将如何强制执行相同的约束:

         0..N <------> 1
<flight>                 <pilot>
         0..N <------> 1

但是随后查询飞行员是否在给定航班上的查询变得非常难看,因为您必须检查两个属性中的每一个。如果属性的数量增加(例如,增加到 15 名空乘人员),查询将变得完全无法管理,并且模式只能勉强管理。

4

6 回答 6

7

其他回复提供了一些有价值的答案。还需要添加两个部分:

首先,ER 建模不仅仅是 ERD。我们倾向于尝试将整个 ER 模型放在一张图上。但完整的 ER 建模远不止适合单个图表的内容。可能存在将关系的基数限制为不少于 10 且不超过 15 的业务规则。但重要的是要认识到这些必须是“业务规则”(即主题规则),而不是出于实际原因施加的设计限制. 一个完整的 ER 模型可以包含所有这些关于数据的业务规则,并且可以在必要时用简单的英语表达这些规则。

首选符号 10..15,因为它更简洁,除非需要更多细节来阐明规则,例如规则存在的原因。

以上暗示了需要做的第二点。这是分析和设计之间的区别。如果以经典方式使用 ER 建模,它是一种数据分析工具,而不是数据库设计工具。“数据分析”是指从以数据为中心的角度分析问题。区分分析和设计,区分问题的特征和解决方案的特征,在正规的 CS 或 IT 教育中教得还不够。把事情做好是绝对关键的。

即使是我们这些意识到差异的人,有时也会将解决方案的特征滑入问题的定义中。这被称为“在盒子里思考”。

如果要绘制数据库设计图表,请不要使用 ERD。使用关系示意图,前提是您设计的数据库是关系数据库。关系示意图包含 ERD 不应包含的功能,例如联结表和外键。不要将 ERD 用作“关系精简版”。事实并非如此。

顺便说一句,另一个答案评论说 ERD 应该可以在任何 DBMS 上实现。这是我刚刚提出的概念的结果,即 ERD 捕获分析而不是设计。

于 2012-09-16T10:24:20.040 回答
2

基数规则本身只是“任何和所有可能的一般规则”的特例。能够表达“任何和所有可能的规则”的仅有的两种语言是人类自然语言(无论你怎么努力,它的缺点都是经常模棱两可和不精确),以及形式谓词逻辑的符号语言。

如何在数据建模的上下文中使用后者,是这本极好的(且值得高度赞扬的)“数据库专业人员应用数学”一书的全部主题。

Halpin 的 ORM 试图提出一种建模语言,它可以覆盖(即有图形符号来表达)比 E/R 更多种类的业务规则。例如,它有用于表达无环图约束的符号(“没有人是他自己的祖先”)。但即使是这种语言也不能表达一切,必须求助于它称为“其他”的最后一类约束,只能用自然语言来描述。

这是语言问题。如果您设计的语言只有极少数的符号(矩形、连接线、零、一和乌鸦脚),并且只能以极少数的方式组合,那么您就不能指望这样的语言能够表达任何可以想象的东西。

于 2012-09-16T10:14:47.567 回答
1

不是您问题的直接答案,但您可能对如何在实际数据库中强制执行这种约束感兴趣......

假设您的航班上最多可以有 2 名飞行员。您可以简单地创建两个“0..N 到 0..1”的关系:

在此处输入图像描述

如果您只需要2 名飞行员,只需将PILOT1_ID和 PILOT2_ID 设为 NOT NULL(并通过 CHECK 确保它们不同)。


但是,正如您已经指出的那样,对于更大的基数,这很快就会变得笨拙,因此需要使用不同的技术。假设您需要将空乘人数限制为15人,您可以这样做......

在此处输入图像描述

...在联结表上具有以下约束:

CHECK (POSITION BETWEEN 1 AND 15)

请注意,在 {FLIGHT_ID, POSITION} 上有一个 UNIQUE 约束,如上U1图所示。

从本质上讲,我们是每次飞行的特定职位的分类服务员。没有两个乘务员可以在同一个航班上占据相同的位置(感谢U1),因此由于每个航班正好有 15 个位置,每个航班的乘务员不能超过 15 个。

不幸的是,没有很好的方法来强制所有职位都被填补,因此每个航班仍然可能少于 15 名乘务员。如果这很重要,您可能必须从应用程序代码中强制执行它。

- - 编辑 - -

要寻找一个空闲位置(用于下一个 INSERT),即使它是两个已填充位置之间的“洞”,您也可以执行以下操作(替换1为所需的 FLIGHT_ID):

SELECT DISTINCT *
FROM (
    SELECT POSITION + 1 FREE_POSITION
    FROM FLIGHT_ATTENDANT
    WHERE FLIGHT_ID = 1
    UNION ALL
    SELECT POSITION - 1 FREE_POSITION
    FROM FLIGHT_ATTENDANT
    WHERE FLIGHT_ID = 1
)
WHERE
    FREE_POSITION NOT IN (
        SELECT POSITION
        FROM FLIGHT_ATTENDANT
        WHERE FLIGHT_ID = 1
    )
ORDER BY FREE_POSITION;

此查询可能有以下结果:

  • 它可以不返回任何行,表示所有位置都是空闲的,因此只需选择有效范围内的任何一个。
  • 它可能会返回行,其中第一行和最后一行可能超出有效范围,因此如果超出,请忽略它们。使用剩余的行之一。如果没有剩余的行,这表明所有位置都已被填满。

这是 Oracle 下的一个有效的 SQL Fiddle 示例,但同样的技术应该适用于任何 DBMS。有更优雅的、特定于 DBMS 的方法来执行这些类型的查询(特别是如果您想要所有空闲位置,而不仅仅是一些),但即使是这种“通用”解决方案对于大多数实际目的来说也应该绰绰有余......

于 2012-09-16T11:59:32.897 回答
0

您有唯一索引(如主键)和非唯一索引:根据您的唯一键定义允许有 1 条记录或多条记录

然后

您有空字段或强制具有值的字段:这里您可能有 0 或 1 个值

结合这两件事,你应该能够知道,为什么他们总是说 0 或更多

ERD 不能总是强制规则,规则通常可以由数据库设计强制,但它总是需要软件的另一层(或至少存储过程)

顺便说一句,关于您的示例,如果您在每次飞行中始终有 2 个飞行员,并且您想通过 db 设计强制执行此规则,您可以简单地创建从 Pilots 表到 Flight 表的 2 个关系,是的,您将有 2 个外键对于同一张桌子,ERD 允许

于 2012-09-16T08:34:57.563 回答
0

E-R图表提供了一种方法来指示每个实体参与关系的次数的限制。
实体集和二元关系集之间的边可以具有关联的最小和最大基数,如:值min...max
表示总参与。的值表示最多参与一次,a的值或表示没有上限。 现在来回答你的问题。您的建模一开始是错误的,因为一名飞行员将参加许多次飞行,而不是您似乎暗示的一次。 此外,如果每个航班正好有 2 名飞行员并且都需要,那么这不是建模为min1max1max*N

1-N关系,但作为航班的 2 个属性(飞行员 id),因为它们永远不会为空或可选(不能有没有 2 名飞行员的航班)。
因此,常数的上限表明设计中存在一些问题,这些问题不足以对您的系统进行建模。

于 2012-09-16T08:48:30.277 回答
0

我遇到过类似的问题。我的场景是让两支足球队参加一场比赛。所以这两个表是“团队”和“夹具”。在夹具表中,我只有一个“team_home”列和一个“team_away”列。我不确定这是否是最好的甚至是正确的方法,但它对我有用。

您是如何实施最大解决方案的?

于 2012-10-03T15:28:25.700 回答