如何在循环引用数据库结构中保持数据完整性?
How to preserve data integrity in circular reference database structure?
我研究了一些数据库规范化和设计方法来正确构建数据,并了解到循环引用不是最佳的,因为它会危及数据完整性。我有一个数据结构,我无法弄清楚如何消除循环引用或确保不引入错误引用。
数据库要求:
- 每种水果都需要特定的水果属性
- 水果配送需要包含的水果类型
- 送水果需要指定所有应用属性
- 水果配送不能引用它不包含的水果类型的属性
我想出的设计如下:
这样做的问题是,可能会在 Delivery 包含 FruitTypeID=1 的地方输入数据,但它链接到 FruitTypeID=2 的属性。
解决此问题的一种可能方法是创建一个触发器,强制一个属性只能链接到相同 FruitType 的交付。但我不喜欢它,因为它看起来很脆弱而且不太可靠。另一种方法是以某种方式消除此数据的圆圈,但我想不出一种仍然符合要求的方法。
所以问题是我如何确保此数据的数据完整性并仍然符合规范?
您没有循环引用。多对一关联指向单边的方向。您拥有的是两条需要保持一致的关联路径。
您可以通过将函数依赖性 AttributeID -> FruitTypeID
和 DeliveryID -> FruitTypeID
反规范化为 Attribute_Fruit
然后创建两个复合 FK 约束来实现:
CREATE TABLE Attribute (
ID INT NOT NULL,
FruitTypeID INT NOT NULL,
Name VARCHAR(255) NOT NULL,
PRIMARY KEY (ID),
FOREIGN KEY (FruitTypeID) REFERENCES FruitType (ID),
UNIQUE KEY (ID, FruitTypeID)
);
CREATE TABLE Delivery (
ID INT NOT NULL,
FruitTypeID INT NOT NULL,
Amount INT NOT NULL,
PRIMARY KEY (ID),
FOREIGN KEY (FruitTypeID) REFERENCES FruitType (ID),
UNIQUE KEY (ID, FruitTypeID)
);
我向 Attribute
和 Delivery
添加了复合唯一键以支持 Attribute_Fruit
table:
上的复合 FK 约束
CREATE TABLE Attribute_Fruit (
AttributeID INT NOT NULL,
DeliveryID INT NOT NULL,
FruitTypeID INT NOT NULL,
PRIMARY KEY (AttributeID, DeliveryID),
FOREIGN KEY (AttributeID, FruitTypeID) REFERENCES Attribute (ID, FruitTypeID),
FOREIGN KEY (DeliveryID, FruitTypeID) REFERENCES Delivery (ID, FruitTypeID)
);
重叠复合 FK 约束将加强您正在寻找的一致性。 FruitTypeID
在 Attribute_Fruit
中在逻辑上是多余的,但对于完整性是必需的,并且没有由于 FK 约束而导致更新异常的风险。
正如您所提到的,触发器是实现相同目标的另一种方法,如果正确实施,它们可靠且不易损坏。但是,我认为上面的方法更简单。
您需要做的是认识到 "fruit attributes" 不是 属性 的交付,而只是水果。因此,您应该将送货建模为与送货关联的多对多关系,并且没有任何水果属性的提及。
更好的是:拼出这些矩形应该意味着什么。也就是说,阐明这些表中的行说明了现实世界[=]中发生了什么事实 23=]。这样做,您会发现自己在思考 问题 。您会发现自己理解 所有 适用于您的业务案例的方面的问题。解决方案将自然而然地出现。并且很可能会涉及比您在这里拥有的更多的矩形。您目前还没有这样做。至少你没有向我们提供任何相关细节。任何试图做出回应的人都将被迫进行猜测,而这些猜测可能是无可救药的。就像我在第一段中自己所做的猜测一样(例如,我假设在应用某些更改之前完成的旧交付中没有必要保留 "attributes" 已经 "delivered" 的记录某些水果的某些属性)。
我研究了一些数据库规范化和设计方法来正确构建数据,并了解到循环引用不是最佳的,因为它会危及数据完整性。我有一个数据结构,我无法弄清楚如何消除循环引用或确保不引入错误引用。
数据库要求:
- 每种水果都需要特定的水果属性
- 水果配送需要包含的水果类型
- 送水果需要指定所有应用属性
- 水果配送不能引用它不包含的水果类型的属性
我想出的设计如下:
解决此问题的一种可能方法是创建一个触发器,强制一个属性只能链接到相同 FruitType 的交付。但我不喜欢它,因为它看起来很脆弱而且不太可靠。另一种方法是以某种方式消除此数据的圆圈,但我想不出一种仍然符合要求的方法。
所以问题是我如何确保此数据的数据完整性并仍然符合规范?
您没有循环引用。多对一关联指向单边的方向。您拥有的是两条需要保持一致的关联路径。
您可以通过将函数依赖性 AttributeID -> FruitTypeID
和 DeliveryID -> FruitTypeID
反规范化为 Attribute_Fruit
然后创建两个复合 FK 约束来实现:
CREATE TABLE Attribute (
ID INT NOT NULL,
FruitTypeID INT NOT NULL,
Name VARCHAR(255) NOT NULL,
PRIMARY KEY (ID),
FOREIGN KEY (FruitTypeID) REFERENCES FruitType (ID),
UNIQUE KEY (ID, FruitTypeID)
);
CREATE TABLE Delivery (
ID INT NOT NULL,
FruitTypeID INT NOT NULL,
Amount INT NOT NULL,
PRIMARY KEY (ID),
FOREIGN KEY (FruitTypeID) REFERENCES FruitType (ID),
UNIQUE KEY (ID, FruitTypeID)
);
我向 Attribute
和 Delivery
添加了复合唯一键以支持 Attribute_Fruit
table:
CREATE TABLE Attribute_Fruit (
AttributeID INT NOT NULL,
DeliveryID INT NOT NULL,
FruitTypeID INT NOT NULL,
PRIMARY KEY (AttributeID, DeliveryID),
FOREIGN KEY (AttributeID, FruitTypeID) REFERENCES Attribute (ID, FruitTypeID),
FOREIGN KEY (DeliveryID, FruitTypeID) REFERENCES Delivery (ID, FruitTypeID)
);
重叠复合 FK 约束将加强您正在寻找的一致性。 FruitTypeID
在 Attribute_Fruit
中在逻辑上是多余的,但对于完整性是必需的,并且没有由于 FK 约束而导致更新异常的风险。
正如您所提到的,触发器是实现相同目标的另一种方法,如果正确实施,它们可靠且不易损坏。但是,我认为上面的方法更简单。
您需要做的是认识到 "fruit attributes" 不是 属性 的交付,而只是水果。因此,您应该将送货建模为与送货关联的多对多关系,并且没有任何水果属性的提及。
更好的是:拼出这些矩形应该意味着什么。也就是说,阐明这些表中的行说明了现实世界[=]中发生了什么事实 23=]。这样做,您会发现自己在思考 问题 。您会发现自己理解 所有 适用于您的业务案例的方面的问题。解决方案将自然而然地出现。并且很可能会涉及比您在这里拥有的更多的矩形。您目前还没有这样做。至少你没有向我们提供任何相关细节。任何试图做出回应的人都将被迫进行猜测,而这些猜测可能是无可救药的。就像我在第一段中自己所做的猜测一样(例如,我假设在应用某些更改之前完成的旧交付中没有必要保留 "attributes" 已经 "delivered" 的记录某些水果的某些属性)。