sql - 从 UML 到 SQL (PostgreSQL)
问题描述
我正在为即将到来的考试进行培训,并且刚刚完成了这个(简单的)练习。
我只是想确保我正确地实现了一切,尤其是具有多重性 1 和 0 的组合 ..*
我的答案:
CREATE TABLE exam.A(
idA integer,
b text NOT NULL,
c float DEFAULT -1.0 CONSTRAINT negative_c CHECK (c < 0.0),
PRIMARY KEY(idA));
CREATE TABLE exam.B(
idB integer,
c integer,
PRIMARY KEY(idB));
CREATE TABLE exam.RelationAandB(
idA integer NOT NULL ON DELETE CASCADE,
idB integer,
b integer,
c text,
FOREIGN KEY (idA) REFERENCES exam.A(idA),
FOREIGN KEY (idB) REFERENCES exam.B(idB),
PRIMARY KEY (idA, idB));
解决方案
您的 SQL 代码非常好,但我看到以下问题:
- 在 UML 类图中,默认情况下属性是必需的。仅当使用多重性表达式 [0..1] 进行限定时,它们才是可选的。因此,所有属性都需要编码为 NOT-NULL 列。但是,您的讲师可能没有意识到这一点,或者正在对“UML 数据模型”使用非标准阅读。
- 字符串值属性 A::b 有一个 "{not empty}" 属性修饰符,它读作要求非空字符串的约束。请注意,具有非空字符串值与强制 (NOT NULL) 不同,因为空字符串 "" 满足 NOT NULL 约束。
- 您还需要在 RelationAandB 表中的 idB 上使用 CASCADE DELETE 规则,因为无论删除 A 还是 B,都必须删除 RelationAandB 中的关联元组。
- 我认为,为了可读性,如果键是非复合的(只有一列),最好将 PRIMARY KEY 声明添加到列定义中。单列 FOREIGN KEY 声明也是如此。
- 许多人认为组合意味着删除依赖,尽管这不是 UML 语义所保证的(参见Aggregation vs Composition),而且它也不是基于常识(参见我下面的评论)。在您的 SQL 代码中,您没有实现这样的依赖关系(“每当删除 A 时,所有依赖的 B 也必须删除”),根据类图的 UML 语义,这是正确的,但可能已经您的讲师的意图,特别是因为他强制要求 B 组件具有 A 复合材料(通过复合材料侧的多重性 1)。这样一个强制性的复合约束意味着,当它们的组合被删除时,组件要么也必须被删除,要么必须重新分配给另一个 (A) 组合。如果您的讲师的意图是应该存在删除依赖项,那么您最好在exam.B 中添加相应的外键声明,从idB 到RelationAandB,并使用CASCADE DELETE 规则:
idB integer FOREIGN KEY REFERENCES exam.RelationAandB CASCADE DELETE,
关于组合是否暗示组合及其组件之间的生命周期依赖的问题,我们必须区分三个抽象级别:1)纯概念(哲学)级别,这应该是数据建模者的常识,2) UML 语义,通常没有精确定义,以及 3)(例如,SQL)代码的级别。在概念层面上,应该清楚存在有和没有这种生命周期依赖的组合,因此存在组合这一事实并不意味着生命周期依赖。
不幸的是,UML 没有定义任何方法来声明组合具有存在依赖的组件。在我的 SO 回答Aggregation vs Composition中,我建议对这种组合使用“不可分割”的刻板印象。
推荐阅读
- c - C 读写 unsigned char (0 - 255) 为 UTF-8
- c - 如何使用“%s\n”而不是“%[^\n]”填充二维数组
- c++ - C++20 概念,需要存在精确的函数签名
- firebase - Firestore 中的数据结构如何影响大型数据集中查询的优化、速度和成本?
- python - 检查数据框中的值是否存在于每一行的另一列中
- apache - Bugzilla 不会将 LDAP 身份验证的用户映射到基于电子邮件的 bugzilla 用户
- python - Dash-plotly 部署为 android 或 IOS 的 apk
- django-forms - 带有自定义表单的 Django UserCreationForm 不起作用
- php - 检查函数是否属于命名空间或全局
- r - 如何使用 geom_bar() 在 R 中创建两个分组列