Han*_*non 5 database-design sql-server referential-integrity
考虑以下设计:
CREATE TABLE dbo.Farmers
(
FarmerName varchar(10) NOT NULL
PRIMARY KEY
);
CREATE TABLE dbo.FarmEquipment
(
FarmEquipmentName varchar(10) NOT NULL
PRIMARY KEY
, CreatorFarmer varchar(10) NOT NULL
FOREIGN KEY REFERENCES dbo.Farmers(FarmerName)
ON UPDATE CASCADE
ON DELETE CASCADE
);
CREATE TABLE dbo.Fields
(
FieldName varchar(10) NOT NULL
, OwnerFarmer varchar(10) NOT NULL
FOREIGN KEY REFERENCES dbo.Farmers(FarmerName)
ON UPDATE CASCADE
ON DELETE CASCADE
, FarmEquipment varchar(10) NOT NULL
FOREIGN KEY REFERENCES dbo.FarmEquipment(FarmEquipmentName)
ON UPDATE CASCADE
ON DELETE CASCADE
);
Run Code Online (Sandbox Code Playgroud)
用例:
Fields
表格中,这样 Farmer Ted 就知道谁拥有他一直在使用的联合收割机。我意识到这是代理键的确切用例,但我试图确定如果您只使用自然键,这将如何工作。
在 SQL Server 中,您实际上无法创建此结构,因为中的ON UPDATE CASCADE
andON UPDATE DELETE
子句会dbo.Fields
产生以下错误消息:
消息 1785,级别 16,状态 0,第 21
行在表“字段”上引入 FOREIGN KEY 约束“FK__Fields__FarmEqui__3AD6B8E2”可能会导致循环或多个级联路径。
指定 ON DELETE NO ACTION 或 ON UPDATE NO ACTION,或修改其他 FOREIGN KEY 约束。消息 1750,级别 16,状态 0,第 21 行
无法创建约束。请参阅以前的错误。
这个模型在 SQL Server 中应该如何表达?
我意识到我可以删除ON UPDATE
条款,但这不是重点。我希望更新和删除级联。
我见过的解决方案是删除外键约束,并通过触发器维护关系完整性。
在外部(或“子”)表上,您需要INSERT
和UPDATE
触发器。如果插入/更新“外键”列,则必须确保该值存在于“父”表的主键中。
在“父”表的UPDATE
主键列上,您必须使用旧值找到任何“子”表(FarmEquipment
并且Fields
都是“子” Farmers
)中的所有行,并将它们更新为新值价值。
在“父”表上,DELETE
您必须检查“子”表以查看是否有任何行使用有问题的主键,并将它们全部删除。
在使用过以这种方式工作的供应商提供的系统后,我不能推荐它。
FarmEquipment
更改Fields
。(在我提到的实际示例中,至少有一个父表具有至少 20 个“FK”关系 - 有时在同一个子表中具有指向不同字段的多个链接。关系的文档不再是内置的。虽然您无法(据我所知)右键单击一个表并查找指向该表的所有外键关系,但很容易找到一个查询来从 SQL Server 的结构表中检索此信息。当通过触发器维护关系时,您几乎必须手动检查触发器来识别所有关系以及精确的定义(“父”表的触发器是您DELETE
可以确定关系是否应该是CASCADE
,,,,或者- 使用外键约束,这可以从“子”表中看到)。NO ACTION
SET NULL
SET DEFAULT
有一些解决方法(触发器代码确实以可查询的形式存在),但它们要求开发人员遵循有关命名约定、查询构造、甚至可能是代码格式的严格规则。即使一个人正在维护代码,并使用模板来设置所有内容,保持所有内容准确无误,以便在进行更改、发现错误并修复时变得更加困难。
我使用的系统通过这种方法已经运行了 10 多年。他们在没有有效外键的环境中启动了他们的应用程序。但即使他们已经到了对新表使用外键的地步,并开始尽可能将它们放在现有表上。只是使用它并不容易。
我怀疑这不符合您的标准;然而,由于它是一个可行的解决方案,我认为它至少值得讨论。
归档时间: |
|
查看次数: |
1497 次 |
最近记录: |