如何避免复合实体键和约束(产品、选项、选项组、特殊订单)出现问题

How to avoid problems with composite entity keys and constraints (Products, Options, Option Groups, Special Orders)

我正在为网上商店建模数据库并且遇到了广告问题。基本上,问题是是否为了简单起见而忽略数据库规范化规则。 以下是问题之前我图表的相关部分。 Database diagram 基本上,产品可以有选项(尺寸、口味、颜色),但只能来自一个选项组。由于一个选项组可以有很多选项,并且使用它的产品可以采用一个子集,因此创建了一个 ProductOption table。接下来我们有一个 SpecialOffers table。接下来,特价商品可以有很多产品,并且产品可以属于许多特价商品,因此关联 table SpecialOfferProducts。所有这一切都可以正常工作,直到特价商品包含有选项的产品。这是我 运行 遇到的问题。我有几个想法。

第一个想法: 在 SpecialOfferProducts 和 ProductOptions 之间创建关联 table。我不喜欢这个想法,因为两个 table 都有复合主键,创建一个 table 有一个由两个复合主键组成的复合主键看起来真的很奇怪,我从来没有见过类似的东西.

第二个想法: 在 SpecialOfferProducts 和 Options 之间创建关联 table。这似乎是错误的,因为 Options 没有直接绑定到 Product。这仍然有效,而且主键会更简单一些。

第三个想法: 这是我最喜欢的一个,但它违反了一些规则。更改 SpecialOfferProducts table。让它有自己的主键,并将 SpecialOffers、Products 和 Options 作为外键。只需使选项外键可为空即可解决问题。当然,问题是我没有在应该的地方建立关联 table 并且正在使外键可为空。这会使我处理所有这些的代码稍微复杂一些,但我仍然觉得这比其他方法简单得多,因为我减少了复合键的数量并且我不必在这种情况下添加另一个 table特价商品使用选项的地方。

我的问题是,以下哪个选项最好?有没有我没有提到的更好的选择?

使用 Martin 风格的符号

OptionGroups 与 table 选项有 (0,n) 关系。选项与 table 选项组具有 (1,1) 关系。这些 table 的目的是存储颜色、大小等信息。一个示例是 OptionGroups 条目颜色,其中选项条目为黑色、白色等。

产品 table 与 table 选项组有 (0,1) 关系。 OptionGroups 与 table 产品有 (0,n) 关系。产品 table 与 table 选项具有 (o,n) 关系。选项 table 与 table 产品具有 (o,n) 关系。多对多关系产生关联 table ProductOptions。 ProductOptions 有一个复合 PK ProductID,OptionsID。这些 table 的目的是允许产品具有(但不一定具有)某个选项组中的选项,但不需要具有该组中的所有选项。

示例 1. 产品没有任何选项,因此 FK Product_OptionGroups 为空。在这种情况下,产品在 ProductOptions table.

中没有任何条目

示例 2. 产品有选项(比如颜色),因此 FK Product_OptionGroups 不为空(具有相应选项组的 ID)。选项组颜色可以有多种颜色,产品可以使用其中一种或多种颜色。产品使用的颜色是 table ProductOptions 中的条目。

SpecialOffer table 与 table 产品具有 (1,n) 关系。产品 table 与 table 特价商品具有 (0,n) 关系。多对多关系创建关联 table SpecialOfferProducts。这个 table 有一个 PK SpecialOfferID,ProductID。 table 具有指示产品数量的 Quantity 属性。

例子。 SpecialOffer A 包括一个产品 A 实例和两个产品 B 实例。

假设产品 A 有选项。现在 SpecialOfferProducts table 必须引用正确的选项。(也许产品可以是蓝色和红色,特价商品只包括红色产品)。这是当前模式不起作用的地方,必须引入额外的 table(想法 1 和 2)或更改现有的 table(想法 3)。

也许你有一些关系(船)/协会不代表table就你的前三个而言:

-- special offer S offers the pairing of P and option O
SpecialOfferProductOption(S, P, O)
-- PK (S, P, O)
-- FK (S, P) to SpecialOfferProducts, FK (P, O) to ProductOptions

您似乎不了解复合键、CK(候选键)、FK(外键)和约束的使用。约束(PK、UNIQUE、FK 等)出现 你设计关系(船)s/associations 足以清楚地描述你的业务情况(由 table 表示) ,根据可能出现的情况。

从 ER 的角度来看,您没有正确应用参与实体(类型)、实体(类型)键和关联实体(类型)的概念。

你对复合 CK 产生了不必要的和模糊的恐惧。即使你想减少复合键的使用,你也应该首先找到一个简单的设计。如果您不想使用复合键,请将 id PK 与其他 CK 一起引入。但请注意,当您将 id 用作 FK 时,不会放弃正确约束它们出现的 table 的义务,以便在必要时根据您使用时需要的约束与其他 id 或列达成一致取而代之的是复合 CK。

First idea: Create an association table between SpecialOfferProducts and ProductOptions. I don't like this idea since both tables have composite primary keys and creating a table that has a composite primary key composed of two composite primary keys seems really weird and I have never seen anything like it.

不清楚你的意思。也许你的意思是上面的(好的)设计。也许你的意思是有重复的产品列;但这并不是好的设计所暗示的。

从 ER 的角度来看:您可能将其视为特殊订单和产品的关系(船舶)/关联。但是实体键不会是复合的,它们会识别特殊订单和产品,并且选项也会参与。或者我们可以使用具体化 relation(ship)s/associations SpecialOfferProducts & ProductOffers 的 ER 概念来关联作为两个参与者的实体。那将使用复合键。 (如果期权不被视为实体,那么 ER 会将其称为弱关系(船舶)/关联实体,并将特殊订单和产品作为标识实体。)无论如何,特殊订单和产品必须就期权达成一致,如果不强制执行通过 FKs 那么它仍然需要约束。

如果您已经(已经)阅读(阅读)了一些关于信息建模和数据库设计的已发表文本(您应该这样做),您将看到复合键的许多用途。

Second idea: Create an association table between SpecialOfferProducts and Options. This seems wrong since Options is not directly tied to Product. Still this would work and the primary key would be a little simpler.

不清楚您所说的 "directly tied"、"seems" 或 "wrong" 是什么意思。

关系 tables relation(ship)s/associations 是值之间的值,其某些子行可以标识某些实体。只需使用相关列并声明相关约束即可。

从 ER 的角度来看:考虑到您似乎对参与者实体(特别优惠与 SpecialOfferProduct)感到困惑,也许这没有实际意义,但是:也许如果您尝试仅使用技术术语来表达自己并且没有混淆那么你会试图说这个设计需要一个约束,即产品选项对出现在 ProductOptions 中,并且约束涉及一个关系(船)/关联,其关联实体 ProductOption 不是参与实体之一,这很混乱。我同意,但这样的设计不是"wrong"。

Third idea: This is the one that I like the most but it violates a few rules. Change the SpecialOfferProducts table. Make it have its own primary key and have SpecialOffers, Products and Options as foreign keys. Simply make the Options foreign key nullable and problem solved.

除了不必要的复杂之外,这种设计很糟糕。它涉及复杂的 table 含义和复杂的约束条件。设置 table 值时,您需要决定何时使用和不使用空值。阅读时,您需要根据行是否为空来弄清楚行的含义。引入 id 或空值(可能在删除列时)不会消除约束剩余列的义务,如果剩余的 FK 约束没有处理的话。通常我们合并 table,同时在不属于每个 CK 的列中引入空值 ——不是你的情况。在这里,您添加的 id 甚至不会避免将产品对和非空选项列值限制在 ProductOptions 中的需要。当存在 NULL 选项列值时,ProductOptions 中仍应存在某些行,有时 SpecialOfferProducts 中不存在某些行。此设计还必须用于处理 NULL 存在的复杂查询。 (您解决的问题。)将其证明为 ER 设计同样存在问题。

PS 1 请用比基本无意义的 "has"、"with"、"uses"、"in" 和 "belong to"——就像您对待客户购买您的产品和特别优惠一样。他们参考关系(船)s/associations和集合,但他们不解释他们。 (同样,基数是关系(船)s/associations 的属性,但不是 explain/characterize 它们。)

PS 2 关于设计的 ER 推理涉及哪些(可能关联的)实体参与关系,而在关系模型视图中 tables 只是捕获任何 n 的 n 元关系(ship)s/associations。所以 ER 观点增加了不必要的区别。这就是为什么 ER-based information modeling & database design approaches are not as effective as fact-based approaches:

This leads to inadequate normalization and constraints, hence redundancy and loss of integrity. Or when those steps are adequately done it leads to the E-R diagram not actually describing the application, which is actually described by the relational database predicates, tables and constraints. Then the E-R diagram is both vague, redundant and wrong.

PS 3 如果 SpecialOfferProducts 包含 "special offer S offers the pairing of P and some option" 行,我们不需要它,因为它是 select S, P from SpecialOfferProductOption。 (这似乎是这种情况,因为您的选项 3 涉及只有一个 table,您称之为 SpecialOfferProducts,但是像这样 table 添加了一个 id。)但是如果它包含行 "special offer S offers product P" 当不是所有 S 的产品选项对都已记录时,情况可能如此,然后您需要它。 (类似的事情出现在决定什么时候是一个实体,例如什么时候应该有一个 table "S is a special option"。)

PS 4

seems really weird and I have never seen anything like it

这就是生活的故事。但在技术背景下,如果我们学习并应用明确定义的基本定义、规则和程序,那么我们 "see" 更多,更清楚。 (并且不要模糊地认为我们模糊地看到了不存在的东西。)并且 "weird" 是一种罕见的情况,我们可以明确证明我们的工具不适用。